From b9116ecf9152f986dc0639675e0400652a66cd1c Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Tue, 15 Oct 2019 17:53:26 -0700 Subject: [PATCH 1/5] Split out ForceCloseHandles into two methods --- .../Azure.Storage.Common/src/Constants.cs | 11 +- .../src/DirectoryClient.cs | 120 +++++++++++--- .../Azure.Storage.Files/src/FileClient.cs | 113 ++++++++++--- .../tests/DirectoryClientTests.cs | 21 ++- .../tests/FileClientTests.cs | 20 ++- .../ForceCloseHandle_Error.json | 108 +++++++++++++ .../ForceCloseHandle_ErrorAsync.json | 108 +++++++++++++ .../ForceCloseHandle_Error.json | 152 ++++++++++++++++++ .../ForceCloseHandle_ErrorAsync.json | 152 ++++++++++++++++++ 9 files changed, 753 insertions(+), 52 deletions(-) create mode 100644 sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_Error.json create mode 100644 sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_ErrorAsync.json create mode 100644 sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_Error.json create mode 100644 sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_ErrorAsync.json diff --git a/sdk/storage/Azure.Storage.Common/src/Constants.cs b/sdk/storage/Azure.Storage.Common/src/Constants.cs index f5e3173b1f57..eaaef915ddfa 100644 --- a/sdk/storage/Azure.Storage.Common/src/Constants.cs +++ b/sdk/storage/Azure.Storage.Common/src/Constants.cs @@ -293,6 +293,11 @@ internal static class File public const string SetHttpHeadersOperationName = "Azure.Storage.Files.FileClient.SetHttpHeaders"; + public const string ForceCloseAllHandlesOperationName = + "Azure.Storage.Files.FileClient.ForceCloseAllHandles"; + public const string ForceCloseHandleOperationName = + "Azure.Storage.Files.FileClient.ForceCloseHandle"; + internal static class Directory { public const string CreateOperationName = @@ -309,8 +314,10 @@ internal static class Directory "Azure.Storage.Files.DirectoryClient.ListFilesAndDirectoriesSegment"; public const string GetHandlesOperationName = "Azure.Storage.Files.DirectoryClient.ListHandles"; - public const string ForceCloseHandlesOperationName = - "Azure.Storage.Files.DirectoryClient.ForceCloseHandles"; + public const string ForceCloseAllHandlesOperationName = + "Azure.Storage.Files.DirectoryClient.ForceCloseAllHandles"; + public const string ForceCloseHandleOperationName = + "Azure.Storage.Files.DirectoryClient.ForceCloseHandle"; } internal static class Service diff --git a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs index cd710227f5dd..d2bd8e68ee4f 100644 --- a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs @@ -1268,10 +1268,8 @@ internal async Task> GetHandlesInternal( #region ForceCloseHandles /// - /// The operation closes a handle or handles opened on a directory - /// or a file at the service. It supports closing a single handle specified by on a file or - /// directory or closing all handles opened on that resource. It optionally supports recursively closing - /// handles on subresources when the resource is a directory. + /// The operation closes a handle opened on a directory + /// or a file at the service. It supports closing a single handle specified by . /// /// This API is intended to be used alongside to force close handles that /// block operations, such as renaming a directory. These handles may have leaked or been lost track of by @@ -1282,11 +1280,87 @@ internal async Task> GetHandlesInternal( /// For more information, see . /// /// - /// Optional. Specifies the handle ID to be closed. If not specified, or if equal to "*", will close all handles. + /// Specifies the handle ID to be closed. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing a + /// segment of the handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual Response ForceCloseHandle( + string handleId, + CancellationToken cancellationToken = default) => + ForceCloseHandlesInternal( + handleId, + null, + null, + false, // async + cancellationToken, + Constants.File.Directory.ForceCloseHandleOperationName) + .EnsureCompleted(); + + /// + /// The operation closes a handle opened on a directory + /// or a file at the service. It supports closing a single handle specified by . + /// + /// This API is intended to be used alongside to force close handles that + /// block operations, such as renaming a directory. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// + /// + /// Specifies the handle ID to be closed. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. /// + /// + /// A describing a + /// segment of the handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual async Task> ForceCloseHandleAsync( + string handleId, + CancellationToken cancellationToken = default) => + await ForceCloseHandlesInternal( + handleId, + null, + null, + true, // async + cancellationToken, + Constants.File.Directory.ForceCloseHandleOperationName) + .ConfigureAwait(false); + + /// + /// The operation closes all handles opened on a directory + /// or a file at the service. It optionally supports recursively closing handles on subresources + /// when the resource is a directory. + /// + /// This API is intended to be used alongside to force close handles that + /// block operations, such as renaming a directory. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -1308,13 +1382,12 @@ internal async Task> GetHandlesInternal( /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseHandles( - string handleId = Constants.CloseAllHandles, + public virtual Response ForceCloseAllHandles( string marker = default, bool? recursive = default, CancellationToken cancellationToken = default) => ForceCloseHandlesInternal( - handleId, + Constants.CloseAllHandles, marker, recursive, false, // async @@ -1322,10 +1395,9 @@ public virtual Response ForceCloseHandles( .EnsureCompleted(); /// - /// The operation closes a handle or handles opened on a directory - /// or a file at the service. It supports closing a single handle specified by on a file or - /// directory or closing all handles opened on that resource. It optionally supports recursively closing - /// handles on subresources when the resource is a directory. + /// The operation closes all handles opened on a directory + /// or a file at the service. It optionally supports recursively closing handles on subresources + /// when the resource is a directory. /// /// This API is intended to be used alongside to force close handles that /// block operations, such as renaming a directory. These handles may have leaked or been lost track of by @@ -1335,12 +1407,9 @@ public virtual Response ForceCloseHandles( /// /// For more information, see . /// - /// - /// Optional. Specifies the handle ID to be closed. If not specified, or if equal to "*", will close all handles. - /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -1362,13 +1431,12 @@ public virtual Response ForceCloseHandles( /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseHandlesAsync( - string handleId = Constants.CloseAllHandles, + public virtual async Task> ForceCloseAllHandlesAsync( string marker = default, bool? recursive = default, CancellationToken cancellationToken = default) => await ForceCloseHandlesInternal( - handleId, + Constants.CloseAllHandles, marker, recursive, true, // async @@ -1376,7 +1444,7 @@ await ForceCloseHandlesInternal( .ConfigureAwait(false); /// - /// The operation closes a handle or handles opened on a directory + /// The operation closes a handle or handles opened on a directory /// or a file at the service. It supports closing a single handle specified by on a file or /// directory or closing all handles opened on that resource. It optionally supports recursively closing /// handles on subresources when the resource is a directory. @@ -1394,7 +1462,7 @@ await ForceCloseHandlesInternal( /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -1411,6 +1479,9 @@ await ForceCloseHandlesInternal( /// Optional to propagate /// notifications that the operation should be cancelled. /// + /// + /// Optional. Used to indicate the name of the operation. + /// /// /// A describing a /// segment of the handles closed. @@ -1424,7 +1495,8 @@ private async Task> ForceCloseHandlesInter string marker, bool? recursive, bool async, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + string operationName = Constants.File.Directory.ForceCloseAllHandlesOperationName) { // TODO Support share snapshot @@ -1447,7 +1519,7 @@ private async Task> ForceCloseHandlesInter handleId: handleId, recursive: recursive, async: async, - operationName: Constants.File.Directory.ForceCloseHandlesOperationName, + operationName: operationName, cancellationToken: cancellationToken) .ConfigureAwait(false); } diff --git a/sdk/storage/Azure.Storage.Files/src/FileClient.cs b/sdk/storage/Azure.Storage.Files/src/FileClient.cs index 58a0ce5118f1..4ebaebd36a1f 100644 --- a/sdk/storage/Azure.Storage.Files/src/FileClient.cs +++ b/sdk/storage/Azure.Storage.Files/src/FileClient.cs @@ -2387,9 +2387,8 @@ internal async Task> GetHandlesInternal( #region ForceCloseHandles /// - /// The operation closes a handle or handles opened on a file - /// at the service. It supports closing a single handle specified by or - /// or closing all handles opened on that resource. + /// The operation closes a handle opened on a file + /// at the service. It supports closing a single handle specified by . /// /// This API is intended to be used alongside to force close handles that /// block operations. These handles may have leaked or been lost track of by @@ -2400,11 +2399,84 @@ internal async Task> GetHandlesInternal( /// For more information, see . /// /// - /// Optional. Specifies the handle ID to be closed. If not specified, or if equal to "*", will close all handles. + /// Specifies the handle ID to be closed. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. /// + /// + /// A describing a + /// segment of the handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual Response ForceCloseHandle( + string handleId, + CancellationToken cancellationToken = default) => + ForceCloseHandlesInternal( + handleId, + null, + false, // async, + cancellationToken, + Constants.File.ForceCloseHandleOperationName) + .EnsureCompleted(); + + /// + /// The operation closes a handle opened on a file + /// at the service. It supports closing a single handle specified by . + /// + /// This API is intended to be used alongside to force close handles that + /// block operations. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// + /// + /// Specifies the handle ID to be closed. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing a + /// segment of the handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual async Task> ForceCloseHandleAsync( + string handleId, + CancellationToken cancellationToken = default) => + await ForceCloseHandlesInternal( + handleId, + null, + true, // async, + cancellationToken, + Constants.File.ForceCloseHandleOperationName) + .ConfigureAwait(false); + + /// + /// The operation closes all handles opened on a file + /// at the service. + /// + /// This API is intended to be used alongside to force close handles that + /// block operations. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -2423,21 +2495,19 @@ internal async Task> GetHandlesInternal( /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseHandles( - string handleId = Constants.CloseAllHandles, + public virtual Response ForceCloseAllHandles( string marker = default, CancellationToken cancellationToken = default) => ForceCloseHandlesInternal( - handleId, + Constants.CloseAllHandles, marker, false, // async, cancellationToken) .EnsureCompleted(); /// - /// The operation closes a handle or handles opened on a file - /// at the service. It supports closing a single handle specified by or - /// or closing all handles opened on that resource. + /// The operation closes all handles opened on a file + /// at the service. /// /// This API is intended to be used alongside to force close handles that /// block operations. These handles may have leaked or been lost track of by @@ -2447,12 +2517,9 @@ public virtual Response ForceCloseHandles( /// /// For more information, see . /// - /// - /// Optional. Specifies the handle ID to be closed. If not specified, or if equal to "*", will close all handles. - /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -2471,12 +2538,11 @@ public virtual Response ForceCloseHandles( /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseHandlesAsync( - string handleId = Constants.CloseAllHandles, + public virtual async Task> ForceCloseAllHandlesAsync( string marker = default, CancellationToken cancellationToken = default) => await ForceCloseHandlesInternal( - handleId, + Constants.CloseAllHandles, marker, true, // async, cancellationToken) @@ -2500,7 +2566,7 @@ await ForceCloseHandlesInternal( /// /// /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The + /// to be closed with the next call to . The /// operation returns a non-empty /// if the operation did not return all items remaining to be /// closed with the current segment. The NextMarker value can @@ -2514,6 +2580,9 @@ await ForceCloseHandlesInternal( /// Optional to propagate /// notifications that the operation should be cancelled. /// + /// + /// Optional. Used to indicate the name of the operation. + /// /// /// A describing a /// segment of the handles closed. @@ -2526,7 +2595,8 @@ private async Task> ForceCloseHandlesInter string handleId, string marker, bool async, - CancellationToken cancellationToken) + CancellationToken cancellationToken, + string operationName = Constants.File.ForceCloseAllHandlesOperationName) { using (Pipeline.BeginLoggingScope(nameof(FileClient))) { @@ -2545,7 +2615,8 @@ private async Task> ForceCloseHandlesInter marker: marker, handleId: handleId, async: async, - cancellationToken: cancellationToken) + cancellationToken: cancellationToken, + operationName: operationName) .ConfigureAwait(false); } catch (Exception ex) diff --git a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs index f5ba85f9b182..27c1fbff57e7 100644 --- a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs @@ -535,7 +535,7 @@ public async Task ForceCloseHandles_Min() using (GetNewDirectory(out DirectoryClient directory)) { // Act - Response response = await directory.ForceCloseHandlesAsync(); + Response response = await directory.ForceCloseAllHandlesAsync(); // Assert Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); @@ -550,7 +550,7 @@ public async Task ForceCloseHandles_Recursive() using (GetNewDirectory(out DirectoryClient directory)) { // Act - Response response = await directory.ForceCloseHandlesAsync(recursive: true); + Response response = await directory.ForceCloseAllHandlesAsync(recursive: true); // Assert Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); @@ -568,12 +568,27 @@ public async Task ForceCloseHandles_Error() // Act await TestHelper.AssertExpectedExceptionAsync( - directory.ForceCloseHandlesAsync(), + directory.ForceCloseAllHandlesAsync(), actualException => Assert.AreEqual("ResourceNotFound", actualException.ErrorCode)); } } + [Test] + public async Task ForceCloseHandle_Error() + { + // Arrange + using (GetNewShare(out ShareClient share)) + { + DirectoryClient directory = InstrumentClient(share.GetDirectoryClient(GetNewDirectoryName())); + AsyncPageable handles = directory.GetHandlesAsync(); + // Act + await TestHelper.AssertExpectedExceptionAsync( + directory.ForceCloseHandleAsync("nonExistantHandleId"), + actualException => Assert.AreEqual("InvalidHeaderValue", actualException.ErrorCode)); + } + } + [Test] public async Task CreateSubdirectoryAsync() { diff --git a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs index 66bf8aa2f5a1..613bb0d06c67 100644 --- a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs @@ -1157,7 +1157,7 @@ public async Task ForceCloseHandles_Min() using (GetNewFile(out FileClient file)) { // Act - Response response = await file.ForceCloseHandlesAsync(); + Response response = await file.ForceCloseAllHandlesAsync(); // Assert Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); @@ -1174,12 +1174,28 @@ public async Task ForceCloseHandles_Error() // Act await TestHelper.AssertExpectedExceptionAsync( - file.ForceCloseHandlesAsync(), + file.ForceCloseAllHandlesAsync(), actualException => Assert.AreEqual("ResourceNotFound", actualException.ErrorCode)); } } + [Test] + public async Task ForceCloseHandle_Error() + { + // Arrange + using (GetNewDirectory(out DirectoryClient directory)) + { + FileClient file = InstrumentClient(directory.GetFileClient(GetNewDirectoryName())); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + file.ForceCloseHandleAsync("nonExistantHandleId"), + actualException => Assert.AreEqual("InvalidHeaderValue", actualException.ErrorCode)); + + } + } + private async Task WaitForCopy(FileClient file, int milliWait = 200) { CopyStatus status = CopyStatus.Pending; diff --git a/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_Error.json b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_Error.json new file mode 100644 index 000000000000..052a65cf5968 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_Error.json @@ -0,0 +1,108 @@ +{ + "Entries": [ + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-128f8a2f-5fed-2f02-8078-8c2deeadc1b5?restype=share", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-0ffe4a3225e07846a4af6fa162e0452a-e058931fcb674040-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "a8c1a478-d489-16e0-fa22-99de55755443", + "x-ms-date": "Wed, 16 Oct 2019 00:35:13 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-share-quota": "1", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:35:13 GMT", + "ETag": "\u00220x8D751D0B5840E05\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:35:13 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "a8c1a478-d489-16e0-fa22-99de55755443", + "x-ms-request-id": "c10f33a0-901a-006d-40b9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-128f8a2f-5fed-2f02-8078-8c2deeadc1b5/test-directory-87d98f1e-5f20-15e6-809e-02c19fb4a3f4?comp=forceclosehandles", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-52be1499b0efbf45ae2bbfa970d9095f-2c9a6f3841ba624a-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "fb2f7cd7-57b1-18b7-beab-28ead21e7745", + "x-ms-date": "Wed, 16 Oct 2019 00:35:13 GMT", + "x-ms-handle-id": "nonExistantHandleId", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "339", + "Content-Type": "application/xml", + "Date": "Wed, 16 Oct 2019 00:35:13 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "fb2f7cd7-57b1-18b7-beab-28ead21e7745", + "x-ms-error-code": "InvalidHeaderValue", + "x-ms-request-id": "c10f33a2-901a-006d-41b9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [ + "\uFEFF\u003C?xml version=\u00221.0\u0022 encoding=\u0022utf-8\u0022?\u003E\u003CError\u003E\u003CCode\u003EInvalidHeaderValue\u003C/Code\u003E\u003CMessage\u003EThe value for one of the HTTP headers is not in the correct format.\n", + "RequestId:c10f33a2-901a-006d-41b9-835b81000000\n", + "Time:2019-10-16T00:35:13.7082763Z\u003C/Message\u003E\u003CHeaderName\u003Ex-ms-handle-id\u003C/HeaderName\u003E\u003CHeaderValue\u003EnonExistantHandleId\u003C/HeaderValue\u003E\u003C/Error\u003E" + ] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-128f8a2f-5fed-2f02-8078-8c2deeadc1b5?restype=share", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-61b9c7103d32e943b33d811502c5629b-1467fe8cfa671c40-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "22ea6804-a784-4143-fc9c-8c40f0409061", + "x-ms-date": "Wed, 16 Oct 2019 00:35:13 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 202, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:35:13 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "22ea6804-a784-4143-fc9c-8c40f0409061", + "x-ms-request-id": "c10f33a3-901a-006d-42b9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + } + ], + "Variables": { + "RandomSeed": "2008209462", + "Storage_TestConfigDefault": "ProductionTenant\njolovstorage\nU2FuaXRpemVk\nhttp://jolovstorage.blob.core.windows.net\nhttp://jolovstorage.file.core.windows.net\nhttp://jolovstorage.queue.core.windows.net\nhttp://jolovstorage.table.core.windows.net\n\n\n\n\nhttp://jolovstorage-secondary.blob.core.windows.net\n\nhttp://jolovstorage-secondary.queue.core.windows.net\nhttp://jolovstorage-secondary.table.core.windows.net\n\nSanitized\n\n\nCloud\nBlobEndpoint=http://jolovstorage.blob.core.windows.net/;QueueEndpoint=http://jolovstorage.queue.core.windows.net/;TableEndpoint=http://jolovstorage.table.core.windows.net/;FileEndpoint=http://jolovstorage.file.core.windows.net/;BlobSecondaryEndpoint=http://jolovstorage-secondary.blob.core.windows.net/;QueueSecondaryEndpoint=http://jolovstorage-secondary.queue.core.windows.net/;TableSecondaryEndpoint=http://jolovstorage-secondary.table.core.windows.net/;AccountName=jolovstorage;AccountKey=Sanitized" + } +} \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_ErrorAsync.json b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_ErrorAsync.json new file mode 100644 index 000000000000..29f8c298c4be --- /dev/null +++ b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/DirectoryClientTests/ForceCloseHandle_ErrorAsync.json @@ -0,0 +1,108 @@ +{ + "Entries": [ + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-012d4a1f-42c6-ecfc-8f8b-972d693775a1?restype=share", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-290d152c301fbb4aa8ac1beb6bb381ce-182dbb4085f1c94d-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "825fd1ff-dd9e-62c3-9cf5-a1dd29df9874", + "x-ms-date": "Wed, 16 Oct 2019 00:35:19 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-share-quota": "1", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:35:18 GMT", + "ETag": "\u00220x8D751D0B8E96575\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:35:19 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "825fd1ff-dd9e-62c3-9cf5-a1dd29df9874", + "x-ms-request-id": "c10f3440-901a-006d-3eb9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-012d4a1f-42c6-ecfc-8f8b-972d693775a1/test-directory-27887d4d-70e9-d7bb-a7de-829754513b43?comp=forceclosehandles", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-ceacd8f37b6f37439601ebe9c8cd3b72-f67c41baec81f84e-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "325e7996-bfc3-8e9a-1688-dbbf5b2c0e4b", + "x-ms-date": "Wed, 16 Oct 2019 00:35:19 GMT", + "x-ms-handle-id": "nonExistantHandleId", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "339", + "Content-Type": "application/xml", + "Date": "Wed, 16 Oct 2019 00:35:18 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "325e7996-bfc3-8e9a-1688-dbbf5b2c0e4b", + "x-ms-error-code": "InvalidHeaderValue", + "x-ms-request-id": "c10f3442-901a-006d-3fb9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [ + "\uFEFF\u003C?xml version=\u00221.0\u0022 encoding=\u0022utf-8\u0022?\u003E\u003CError\u003E\u003CCode\u003EInvalidHeaderValue\u003C/Code\u003E\u003CMessage\u003EThe value for one of the HTTP headers is not in the correct format.\n", + "RequestId:c10f3442-901a-006d-3fb9-835b81000000\n", + "Time:2019-10-16T00:35:19.3995880Z\u003C/Message\u003E\u003CHeaderName\u003Ex-ms-handle-id\u003C/HeaderName\u003E\u003CHeaderValue\u003EnonExistantHandleId\u003C/HeaderValue\u003E\u003C/Error\u003E" + ] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-012d4a1f-42c6-ecfc-8f8b-972d693775a1?restype=share", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-2fc2133e4c50d0499b6469eefaac9a97-55369a588829f447-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "da00e2b9-08f2-e67f-789f-814f1743704b", + "x-ms-date": "Wed, 16 Oct 2019 00:35:19 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 202, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:35:18 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "da00e2b9-08f2-e67f-789f-814f1743704b", + "x-ms-request-id": "c10f3443-901a-006d-40b9-835b81000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + } + ], + "Variables": { + "RandomSeed": "1515064791", + "Storage_TestConfigDefault": "ProductionTenant\njolovstorage\nU2FuaXRpemVk\nhttp://jolovstorage.blob.core.windows.net\nhttp://jolovstorage.file.core.windows.net\nhttp://jolovstorage.queue.core.windows.net\nhttp://jolovstorage.table.core.windows.net\n\n\n\n\nhttp://jolovstorage-secondary.blob.core.windows.net\n\nhttp://jolovstorage-secondary.queue.core.windows.net\nhttp://jolovstorage-secondary.table.core.windows.net\n\nSanitized\n\n\nCloud\nBlobEndpoint=http://jolovstorage.blob.core.windows.net/;QueueEndpoint=http://jolovstorage.queue.core.windows.net/;TableEndpoint=http://jolovstorage.table.core.windows.net/;FileEndpoint=http://jolovstorage.file.core.windows.net/;BlobSecondaryEndpoint=http://jolovstorage-secondary.blob.core.windows.net/;QueueSecondaryEndpoint=http://jolovstorage-secondary.queue.core.windows.net/;TableSecondaryEndpoint=http://jolovstorage-secondary.table.core.windows.net/;AccountName=jolovstorage;AccountKey=Sanitized" + } +} \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_Error.json b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_Error.json new file mode 100644 index 000000000000..a55f4a4e240d --- /dev/null +++ b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_Error.json @@ -0,0 +1,152 @@ +{ + "Entries": [ + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-94acab9d-b00d-6f3d-91e2-d8ede8b9baf8?restype=share", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-5a1b24a29e35c3489231b5ef1b8c7a1c-d2cb349f92e47a4d-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "229f8633-50c7-2a10-2880-a63d3c057c2f", + "x-ms-date": "Wed, 16 Oct 2019 00:42:16 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-share-quota": "1", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:15 GMT", + "ETag": "\u00220x8D751D1B17AF3C9\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:42:16 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "229f8633-50c7-2a10-2880-a63d3c057c2f", + "x-ms-request-id": "443dd996-801a-0072-69ba-838091000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-94acab9d-b00d-6f3d-91e2-d8ede8b9baf8/test-directory-24592af0-7ece-9316-91d3-ed903670cbb3?restype=directory", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-613f394ab90a6b4dab5ce97179621f74-968c2cac1dc9084b-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "79db49ff-cc84-b518-700c-90f3627ff3b7", + "x-ms-date": "Wed, 16 Oct 2019 00:42:16 GMT", + "x-ms-file-attributes": "None", + "x-ms-file-creation-time": "Now", + "x-ms-file-last-write-time": "Now", + "x-ms-file-permission": "Inherit", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:15 GMT", + "ETag": "\u00220x8D751D1B1817241\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:42:16 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "79db49ff-cc84-b518-700c-90f3627ff3b7", + "x-ms-file-attributes": "Directory", + "x-ms-file-change-time": "2019-10-16T00:42:16.4279873Z", + "x-ms-file-creation-time": "2019-10-16T00:42:16.4279873Z", + "x-ms-file-id": "13835128424026341376", + "x-ms-file-last-write-time": "2019-10-16T00:42:16.4279873Z", + "x-ms-file-parent-id": "0", + "x-ms-file-permission-key": "2514336555444402195*5350155227445161882", + "x-ms-request-id": "443dd998-801a-0072-6aba-838091000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-94acab9d-b00d-6f3d-91e2-d8ede8b9baf8/test-directory-24592af0-7ece-9316-91d3-ed903670cbb3/test-directory-4b4cf3b5-1b4b-5916-f94b-d2f216412eb6?comp=forceclosehandles", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-f1b55bd0606ed74c8b554ea189da58b8-f753bd996fbe5c4b-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "711eb0e9-508f-e455-3382-7f39fa269e2e", + "x-ms-date": "Wed, 16 Oct 2019 00:42:16 GMT", + "x-ms-handle-id": "nonExistantHandleId", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "339", + "Content-Type": "application/xml", + "Date": "Wed, 16 Oct 2019 00:42:15 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "711eb0e9-508f-e455-3382-7f39fa269e2e", + "x-ms-error-code": "InvalidHeaderValue", + "x-ms-request-id": "443dd999-801a-0072-6bba-838091000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [ + "\uFEFF\u003C?xml version=\u00221.0\u0022 encoding=\u0022utf-8\u0022?\u003E\u003CError\u003E\u003CCode\u003EInvalidHeaderValue\u003C/Code\u003E\u003CMessage\u003EThe value for one of the HTTP headers is not in the correct format.\n", + "RequestId:443dd999-801a-0072-6bba-838091000000\n", + "Time:2019-10-16T00:42:16.4784928Z\u003C/Message\u003E\u003CHeaderName\u003Ex-ms-handle-id\u003C/HeaderName\u003E\u003CHeaderValue\u003EnonExistantHandleId\u003C/HeaderValue\u003E\u003C/Error\u003E" + ] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-94acab9d-b00d-6f3d-91e2-d8ede8b9baf8?restype=share", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-c4d88793004e7e4a9d8a549dcce6d0bc-603369fcfdb0e942-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "6609ff9f-bd22-e626-f6ad-ba11d2f52ab2", + "x-ms-date": "Wed, 16 Oct 2019 00:42:16 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 202, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:15 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "6609ff9f-bd22-e626-f6ad-ba11d2f52ab2", + "x-ms-request-id": "443dd99a-801a-0072-6cba-838091000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + } + ], + "Variables": { + "RandomSeed": "350272571", + "Storage_TestConfigDefault": "ProductionTenant\njolovstorage\nU2FuaXRpemVk\nhttp://jolovstorage.blob.core.windows.net\nhttp://jolovstorage.file.core.windows.net\nhttp://jolovstorage.queue.core.windows.net\nhttp://jolovstorage.table.core.windows.net\n\n\n\n\nhttp://jolovstorage-secondary.blob.core.windows.net\n\nhttp://jolovstorage-secondary.queue.core.windows.net\nhttp://jolovstorage-secondary.table.core.windows.net\n\nSanitized\n\n\nCloud\nBlobEndpoint=http://jolovstorage.blob.core.windows.net/;QueueEndpoint=http://jolovstorage.queue.core.windows.net/;TableEndpoint=http://jolovstorage.table.core.windows.net/;FileEndpoint=http://jolovstorage.file.core.windows.net/;BlobSecondaryEndpoint=http://jolovstorage-secondary.blob.core.windows.net/;QueueSecondaryEndpoint=http://jolovstorage-secondary.queue.core.windows.net/;TableSecondaryEndpoint=http://jolovstorage-secondary.table.core.windows.net/;AccountName=jolovstorage;AccountKey=Sanitized" + } +} \ No newline at end of file diff --git a/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_ErrorAsync.json b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_ErrorAsync.json new file mode 100644 index 000000000000..21140eebe0af --- /dev/null +++ b/sdk/storage/Azure.Storage.Files/tests/SessionRecords/FileClientTests/ForceCloseHandle_ErrorAsync.json @@ -0,0 +1,152 @@ +{ + "Entries": [ + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-7182f0d4-9cd4-3c73-9eed-6cc4ea4e6f67?restype=share", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-72bcf9f9e2488a4ead5883b19f034fdc-9a4817d9e5e55c4c-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "f18feefe-aeef-4b49-7b76-5ea9193f7794", + "x-ms-date": "Wed, 16 Oct 2019 00:42:57 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-share-quota": "1", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:56 GMT", + "ETag": "\u00220x8D751D1C9C77868\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:42:57 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "f18feefe-aeef-4b49-7b76-5ea9193f7794", + "x-ms-request-id": "5893820b-601a-0051-5eba-83ef5a000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-7182f0d4-9cd4-3c73-9eed-6cc4ea4e6f67/test-directory-dbd84f0c-464d-39f1-2417-9a67f4e991e1?restype=directory", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-11a65645bbb31b478f6b02c0fe9b2133-161eecedd81b6a4f-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "5b7d13f5-abe4-b84c-fd55-ccd814e25692", + "x-ms-date": "Wed, 16 Oct 2019 00:42:57 GMT", + "x-ms-file-attributes": "None", + "x-ms-file-creation-time": "Now", + "x-ms-file-last-write-time": "Now", + "x-ms-file-permission": "Inherit", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:56 GMT", + "ETag": "\u00220x8D751D1C9CEC3EA\u0022", + "Last-Modified": "Wed, 16 Oct 2019 00:42:57 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "5b7d13f5-abe4-b84c-fd55-ccd814e25692", + "x-ms-file-attributes": "Directory", + "x-ms-file-change-time": "2019-10-16T00:42:57.2000234Z", + "x-ms-file-creation-time": "2019-10-16T00:42:57.2000234Z", + "x-ms-file-id": "13835128424026341376", + "x-ms-file-last-write-time": "2019-10-16T00:42:57.2000234Z", + "x-ms-file-parent-id": "0", + "x-ms-file-permission-key": "2514336555444402195*5350155227445161882", + "x-ms-request-id": "5893820d-601a-0051-5fba-83ef5a000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-7182f0d4-9cd4-3c73-9eed-6cc4ea4e6f67/test-directory-dbd84f0c-464d-39f1-2417-9a67f4e991e1/test-directory-46427de5-7c7a-8ed5-d7d1-9701dabefd02?comp=forceclosehandles", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-4ccb9e4c0381d24098c60b1804e5922f-c8700348a543b04d-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "bf4dd9f5-0ae0-791d-3eef-8313134bde3f", + "x-ms-date": "Wed, 16 Oct 2019 00:42:57 GMT", + "x-ms-handle-id": "nonExistantHandleId", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "339", + "Content-Type": "application/xml", + "Date": "Wed, 16 Oct 2019 00:42:56 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "bf4dd9f5-0ae0-791d-3eef-8313134bde3f", + "x-ms-error-code": "InvalidHeaderValue", + "x-ms-request-id": "5893820e-601a-0051-60ba-83ef5a000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [ + "\uFEFF\u003C?xml version=\u00221.0\u0022 encoding=\u0022utf-8\u0022?\u003E\u003CError\u003E\u003CCode\u003EInvalidHeaderValue\u003C/Code\u003E\u003CMessage\u003EThe value for one of the HTTP headers is not in the correct format.\n", + "RequestId:5893820e-601a-0051-60ba-83ef5a000000\n", + "Time:2019-10-16T00:42:57.2412783Z\u003C/Message\u003E\u003CHeaderName\u003Ex-ms-handle-id\u003C/HeaderName\u003E\u003CHeaderValue\u003EnonExistantHandleId\u003C/HeaderValue\u003E\u003C/Error\u003E" + ] + }, + { + "RequestUri": "http://jolovstorage.file.core.windows.net/test-share-7182f0d4-9cd4-3c73-9eed-6cc4ea4e6f67?restype=share", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "traceparent": "00-b4cf7ea5edd889428ea96b4f60a4ecb8-54f3b0cd0d76da4c-00", + "User-Agent": [ + "azsdk-net-Storage.Files/12.0.0-dev.20191015.1\u002B57ef4720914a34ab66322af016d927dc4992c5c9", + "(.NET Core 4.6.28008.01; Microsoft Windows 10.0.18362 )" + ], + "x-ms-client-request-id": "010b34df-3d71-bc21-e5f8-a27cb3e9a83a", + "x-ms-date": "Wed, 16 Oct 2019 00:42:57 GMT", + "x-ms-return-client-request-id": "true", + "x-ms-version": "2019-02-02" + }, + "RequestBody": null, + "StatusCode": 202, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Wed, 16 Oct 2019 00:42:56 GMT", + "Server": [ + "Windows-Azure-File/1.0", + "Microsoft-HTTPAPI/2.0" + ], + "x-ms-client-request-id": "010b34df-3d71-bc21-e5f8-a27cb3e9a83a", + "x-ms-request-id": "5893820f-601a-0051-61ba-83ef5a000000", + "x-ms-version": "2019-02-02" + }, + "ResponseBody": [] + } + ], + "Variables": { + "RandomSeed": "1605347705", + "Storage_TestConfigDefault": "ProductionTenant\njolovstorage\nU2FuaXRpemVk\nhttp://jolovstorage.blob.core.windows.net\nhttp://jolovstorage.file.core.windows.net\nhttp://jolovstorage.queue.core.windows.net\nhttp://jolovstorage.table.core.windows.net\n\n\n\n\nhttp://jolovstorage-secondary.blob.core.windows.net\n\nhttp://jolovstorage-secondary.queue.core.windows.net\nhttp://jolovstorage-secondary.table.core.windows.net\n\nSanitized\n\n\nCloud\nBlobEndpoint=http://jolovstorage.blob.core.windows.net/;QueueEndpoint=http://jolovstorage.queue.core.windows.net/;TableEndpoint=http://jolovstorage.table.core.windows.net/;FileEndpoint=http://jolovstorage.file.core.windows.net/;BlobSecondaryEndpoint=http://jolovstorage-secondary.blob.core.windows.net/;QueueSecondaryEndpoint=http://jolovstorage-secondary.queue.core.windows.net/;TableSecondaryEndpoint=http://jolovstorage-secondary.table.core.windows.net/;AccountName=jolovstorage;AccountKey=Sanitized" + } +} \ No newline at end of file From 26835e1965bbdb0b0b40e7a7b17f2d346c70bf94 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 16 Oct 2019 12:16:46 -0700 Subject: [PATCH 2/5] Update return type and do looping ourselves for All API --- .../src/DirectoryClient.cs | 109 +++++++++++------- .../Azure.Storage.Files/src/FileClient.cs | 102 +++++++++------- .../tests/DirectoryClientTests.cs | 8 +- .../tests/FileClientTests.cs | 8 +- 4 files changed, 137 insertions(+), 90 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs index d2bd8e68ee4f..f6a59c9f93b5 100644 --- a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs @@ -1287,14 +1287,14 @@ internal async Task> GetHandlesInternal( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// A describing the status of the + /// operation. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseHandle( + public virtual Response ForceCloseHandle( string handleId, CancellationToken cancellationToken = default) => ForceCloseHandlesInternal( @@ -1304,7 +1304,8 @@ public virtual Response ForceCloseHandle( false, // async cancellationToken, Constants.File.Directory.ForceCloseHandleOperationName) - .EnsureCompleted(); + .EnsureCompleted() + .GetRawResponse(); /// /// The operation closes a handle opened on a directory @@ -1326,24 +1327,25 @@ public virtual Response ForceCloseHandle( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// A describing the status of the + /// operation. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseHandleAsync( + public virtual async Task ForceCloseHandleAsync( string handleId, CancellationToken cancellationToken = default) => - await ForceCloseHandlesInternal( + (await ForceCloseHandlesInternal( handleId, null, null, true, // async cancellationToken, Constants.File.Directory.ForceCloseHandleOperationName) - .ConfigureAwait(false); + .ConfigureAwait(false)) + .GetRawResponse(); /// /// The operation closes all handles opened on a directory @@ -1358,15 +1360,6 @@ await ForceCloseHandlesInternal( /// /// For more information, see . /// - /// - /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The - /// operation returns a non-empty - /// if the operation did not return all items remaining to be - /// closed with the current segment. The NextMarker value can - /// be used as the value for the parameter - /// in a subsequent call to request the closure of the next segment of handles. - /// /// /// Optional. A boolean value that specifies if the operation should also apply to the files and subdirectories of the directory specified. /// @@ -1375,27 +1368,23 @@ await ForceCloseHandlesInternal( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// The number of handles closed. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseAllHandles( - string marker = default, + public virtual int ForceCloseAllHandles( bool? recursive = default, CancellationToken cancellationToken = default) => - ForceCloseHandlesInternal( - Constants.CloseAllHandles, - marker, + ForceCloseAllHandlesInternal( recursive, false, // async cancellationToken) .EnsureCompleted(); /// - /// The operation closes all handles opened on a directory + /// The operation closes all handles opened on a directory /// or a file at the service. It optionally supports recursively closing handles on subresources /// when the resource is a directory. /// @@ -1407,15 +1396,6 @@ public virtual Response ForceCloseAllHandles( /// /// For more information, see . /// - /// - /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The - /// operation returns a non-empty - /// if the operation did not return all items remaining to be - /// closed with the current segment. The NextMarker value can - /// be used as the value for the parameter - /// in a subsequent call to request the closure of the next segment of handles. - /// /// /// Optional. A boolean value that specifies if the operation should also apply to the files and subdirectories of the directory specified. /// @@ -1424,25 +1404,70 @@ public virtual Response ForceCloseAllHandles( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// The number of handles closed. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseAllHandlesAsync( - string marker = default, + public virtual async Task ForceCloseAllHandlesAsync( bool? recursive = default, CancellationToken cancellationToken = default) => - await ForceCloseHandlesInternal( - Constants.CloseAllHandles, - marker, + await ForceCloseAllHandlesInternal( recursive, true, // async cancellationToken) .ConfigureAwait(false); + /// + /// The operation closes all handles opened on a directory + /// or a file at the service. It optionally supports recursively closing handles on subresources + /// when the resource is a directory. + /// + /// This API is intended to be used alongside to force close handles that + /// block operations. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// + /// + /// Optional. A boolean value that specifies if the operation should also apply to the files and subdirectories of the directory specified. + /// + /// + /// Whether to invoke the operation asynchronously. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// The number of handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + private async Task ForceCloseAllHandlesInternal( + bool? recursive, + bool async, + CancellationToken cancellationToken) + { + int handlesClosed = 0; + string marker = null; + do + { + Response response = + await ForceCloseHandlesInternal(Constants.CloseAllHandles, marker, recursive, async, cancellationToken).ConfigureAwait(false); + marker = response.Value.Marker; + handlesClosed += response.Value.NumberOfHandlesClosed; + + } while (!string.IsNullOrEmpty(marker)); + + return handlesClosed; + } + /// /// The operation closes a handle or handles opened on a directory /// or a file at the service. It supports closing a single handle specified by on a file or diff --git a/sdk/storage/Azure.Storage.Files/src/FileClient.cs b/sdk/storage/Azure.Storage.Files/src/FileClient.cs index 4ebaebd36a1f..ff969c71ae83 100644 --- a/sdk/storage/Azure.Storage.Files/src/FileClient.cs +++ b/sdk/storage/Azure.Storage.Files/src/FileClient.cs @@ -2406,14 +2406,14 @@ internal async Task> GetHandlesInternal( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// A describing the status of the + /// operation. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseHandle( + public virtual Response ForceCloseHandle( string handleId, CancellationToken cancellationToken = default) => ForceCloseHandlesInternal( @@ -2422,7 +2422,8 @@ public virtual Response ForceCloseHandle( false, // async, cancellationToken, Constants.File.ForceCloseHandleOperationName) - .EnsureCompleted(); + .EnsureCompleted() + .GetRawResponse(); /// /// The operation closes a handle opened on a file @@ -2444,23 +2445,24 @@ public virtual Response ForceCloseHandle( /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// A describing the status of the + /// operation. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseHandleAsync( + public virtual async Task ForceCloseHandleAsync( string handleId, CancellationToken cancellationToken = default) => - await ForceCloseHandlesInternal( + (await ForceCloseHandlesInternal( handleId, null, true, // async, cancellationToken, Constants.File.ForceCloseHandleOperationName) - .ConfigureAwait(false); + .ConfigureAwait(false)). + GetRawResponse(); /// /// The operation closes all handles opened on a file @@ -2474,33 +2476,20 @@ await ForceCloseHandlesInternal( /// /// For more information, see . /// - /// - /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The - /// operation returns a non-empty - /// if the operation did not return all items remaining to be - /// closed with the current segment. The NextMarker value can - /// be used as the value for the parameter - /// in a subsequent call to request the closure of the next segment of handles. - /// /// /// Optional to propagate /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// The number of handles closed. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual Response ForceCloseAllHandles( - string marker = default, + public virtual int ForceCloseAllHandles( CancellationToken cancellationToken = default) => - ForceCloseHandlesInternal( - Constants.CloseAllHandles, - marker, + ForceCloseAllHandlesInternal( false, // async, cancellationToken) .EnsureCompleted(); @@ -2517,37 +2506,68 @@ public virtual Response ForceCloseAllHandles( /// /// For more information, see . /// - /// - /// An optional string value that identifies the segment of the handles - /// to be closed with the next call to . The - /// operation returns a non-empty - /// if the operation did not return all items remaining to be - /// closed with the current segment. The NextMarker value can - /// be used as the value for the parameter - /// in a subsequent call to request the closure of the next segment of handles. - /// /// /// Optional to propagate /// notifications that the operation should be cancelled. /// /// - /// A describing a - /// segment of the handles closed. + /// The number of handles closed. /// /// /// A will be thrown if /// a failure occurs. /// - public virtual async Task> ForceCloseAllHandlesAsync( - string marker = default, + public virtual async Task ForceCloseAllHandlesAsync( CancellationToken cancellationToken = default) => - await ForceCloseHandlesInternal( - Constants.CloseAllHandles, - marker, + await ForceCloseAllHandlesInternal( true, // async, cancellationToken) .ConfigureAwait(false); + /// + /// The operation closes a handle or handles opened on a file + /// at the service. It supports closing all handles opened on that resource. + /// + /// This API is intended to be used alongside to force close handles that + /// block operations. These handles may have leaked or been lost track of by + /// SMB clients. The API has client-side impact on the handle being closed, including user visible + /// errors due to failed attempts to read or write files. This API is not intended for use as a replacement + /// or alternative for SMB close. + /// + /// For more information, see . + /// + /// + /// Whether to invoke the operation asynchronously. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// The number of handles closed. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + private async Task ForceCloseAllHandlesInternal( + bool async, + CancellationToken cancellationToken) + { + int handlesClosed = 0; + string marker = null; + do + { + Response response = + await ForceCloseHandlesInternal(Constants.CloseAllHandles, marker, async, cancellationToken).ConfigureAwait(false); + marker = response.Value.Marker; + handlesClosed += response.Value.NumberOfHandlesClosed; + + } while (!string.IsNullOrEmpty(marker)); + + return handlesClosed; + } + /// /// The operation closes a handle or handles opened on a file /// at the service. It supports closing a single handle specified by or diff --git a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs index 27c1fbff57e7..8f9a550d5544 100644 --- a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs @@ -535,10 +535,10 @@ public async Task ForceCloseHandles_Min() using (GetNewDirectory(out DirectoryClient directory)) { // Act - Response response = await directory.ForceCloseAllHandlesAsync(); + int handlesClosed = await directory.ForceCloseAllHandlesAsync(); // Assert - Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); + Assert.AreEqual(0, handlesClosed); } } @@ -550,10 +550,10 @@ public async Task ForceCloseHandles_Recursive() using (GetNewDirectory(out DirectoryClient directory)) { // Act - Response response = await directory.ForceCloseAllHandlesAsync(recursive: true); + int handlesClosed = await directory.ForceCloseAllHandlesAsync(recursive: true); // Assert - Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); + Assert.AreEqual(0, handlesClosed); } } diff --git a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs index 613bb0d06c67..f67cf995e042 100644 --- a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs @@ -21,7 +21,7 @@ namespace Azure.Storage.Files.Test public class FileClientTests : FileTestBase { public FileClientTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + : base(async, RecordedTestMode.Record /* RecordedTestMode.Record /* to re-record */) { } @@ -1126,6 +1126,8 @@ public async Task ListHandles_Min() // Arrange using (GetNewFile(out FileClient file)) { + await file.DownloadAsync(); + await file.GetPropertiesAsync(); // Act IList handles = await file.GetHandlesAsync().ToListAsync(); @@ -1157,10 +1159,10 @@ public async Task ForceCloseHandles_Min() using (GetNewFile(out FileClient file)) { // Act - Response response = await file.ForceCloseAllHandlesAsync(); + int handlesClosed = await file.ForceCloseAllHandlesAsync(); // Assert - Assert.AreEqual(0, response.Value.NumberOfHandlesClosed); + Assert.AreEqual(0, handlesClosed); } } From 58cd2850ccca31c4cabdcd728aeeda0e7379e3dd Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 16 Oct 2019 13:58:29 -0700 Subject: [PATCH 3/5] rebase --- sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs index 8f9a550d5544..660c0ad53565 100644 --- a/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/DirectoryClientTests.cs @@ -581,7 +581,7 @@ public async Task ForceCloseHandle_Error() using (GetNewShare(out ShareClient share)) { DirectoryClient directory = InstrumentClient(share.GetDirectoryClient(GetNewDirectoryName())); - AsyncPageable handles = directory.GetHandlesAsync(); + AsyncPageable handles = directory.GetHandlesAsync(); // Act await TestHelper.AssertExpectedExceptionAsync( directory.ForceCloseHandleAsync("nonExistantHandleId"), From ba7e239c47cc5816beeaa91ccf8a5b2f44b90317 Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 16 Oct 2019 20:37:15 -0700 Subject: [PATCH 4/5] fix nits --- sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs | 8 +++++++- sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs index f6a59c9f93b5..4f18143e7e02 100644 --- a/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files/src/DirectoryClient.cs @@ -1459,7 +1459,13 @@ private async Task ForceCloseAllHandlesInternal( do { Response response = - await ForceCloseHandlesInternal(Constants.CloseAllHandles, marker, recursive, async, cancellationToken).ConfigureAwait(false); + await ForceCloseHandlesInternal( + Constants.CloseAllHandles, + marker, + recursive, + async, + cancellationToken) + .ConfigureAwait(false); marker = response.Value.Marker; handlesClosed += response.Value.NumberOfHandlesClosed; diff --git a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs index f67cf995e042..0e4540b95651 100644 --- a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs @@ -21,7 +21,7 @@ namespace Azure.Storage.Files.Test public class FileClientTests : FileTestBase { public FileClientTests(bool async) - : base(async, RecordedTestMode.Record /* RecordedTestMode.Record /* to re-record */) + : base(async, null /* RecordedTestMode.Record /* to re-record */) { } From 22c15992a2ba15d9d37c173ca735a4c58391230f Mon Sep 17 00:00:00 2001 From: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> Date: Wed, 16 Oct 2019 20:41:53 -0700 Subject: [PATCH 5/5] update test --- sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs index 0e4540b95651..467f50249e9d 100644 --- a/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files/tests/FileClientTests.cs @@ -1126,8 +1126,6 @@ public async Task ListHandles_Min() // Arrange using (GetNewFile(out FileClient file)) { - await file.DownloadAsync(); - await file.GetPropertiesAsync(); // Act IList handles = await file.GetHandlesAsync().ToListAsync();