From 0f3f8066bd46ecef637b839d88711d600f17874a Mon Sep 17 00:00:00 2001 From: m-nash <64171366+m-nash@users.noreply.github.com> Date: Mon, 22 Mar 2021 10:16:12 -0700 Subject: [PATCH 01/15] WIP --- .../src/ArmResponse.cs | 46 --- .../src/GenericResourceOperations.cs | 14 +- .../src/IDeletableResource.cs | 4 +- .../src/{ => Operation}/ArmOperation.cs | 40 +- .../src/Operation/ArmOperationHelpers.cs | 369 ++++++++++++++++++ .../PhArmOperation.cs | 1 - .../src/Operation/ValueArmOperation.cs | 48 +++ .../VoidArmOperation.cs} | 21 +- .../src/ResourceGroupOperations.cs | 16 +- .../src/Response/ArmResponse.cs | 60 +++ .../{Adapters => Response}/PhArmResponse.cs | 0 .../src/Response/ValueArmResponse.cs | 24 ++ .../src/Response/VoidArmResponse.cs | 54 +++ .../src/UpdateResourceGroupOperation.cs | 20 + .../tests/Unit/ArmResponseTests.cs | 3 +- .../tests/Unit/ResourceTypeFilterTests.cs | 4 +- 16 files changed, 629 insertions(+), 95 deletions(-) delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{ => Operation}/ArmOperation.cs (75%) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{Placeholder => Operation}/PhArmOperation.cs (99%) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{ArmVoidOperation.cs => Operation/VoidArmOperation.cs} (85%) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{Adapters => Response}/PhArmResponse.cs (100%) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs deleted file mode 100644 index c9f4e005822d..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmResponse.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; - -namespace Azure.ResourceManager.Core -{ - /// - /// A class representing a response object from azure resource manager service. - /// - public sealed class ArmResponse : ArmResponse - { - private readonly Response _response; - - /// - /// Initializes a new instance of the class. - /// - /// The azure response object to wrap. - /// If is null. - public ArmResponse(Response response) - { - if (response is null) - throw new ArgumentNullException(nameof(response)); - - _response = response; - } - - /// - public override Response Value => _response; - - /// - public override Response GetRawResponse() - { - return _response; - } - } - - /// - /// A class representing a response object from azure resource manager service. - /// - /// The operations object return by the api call. - [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Allowed when we have a generic version of the same type")] - public abstract class ArmResponse : Response - { - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs index 733cab70e87f..bf2381da4074 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs @@ -41,9 +41,9 @@ internal GenericResourceOperations(ResourceOperationsBase operations, ResourceId /// /// A token allowing immediate cancellation of any blocking call performed during the deletion. /// The status of the delete operation. - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDeleteById(Id, _apiVersion, cancellationToken).WaitForCompletion(cancellationToken)); + return ArmResponse.FromResponse(Operations.StartDeleteById(Id, _apiVersion, cancellationToken).WaitForCompletion(cancellationToken)); } /// @@ -51,11 +51,11 @@ public ArmResponse Delete(CancellationToken cancellationToken = defaul /// /// A token allowing immediate cancellation of any blocking call performed during the deletion. /// A that on completion returns the status of the delete operation. - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { var operation = await Operations.StartDeleteByIdAsync(Id, _apiVersion, cancellationToken).ConfigureAwait(false); var result = await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); - return new ArmResponse(result); + return ArmResponse.FromResponse(result); } /// @@ -69,7 +69,7 @@ public async Task> DeleteAsync(CancellationToken cancellat /// public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDeleteById(Id, _apiVersion, cancellationToken)); + return new VoidArmOperation(Operations.StartDeleteById(Id, _apiVersion, cancellationToken)); } /// @@ -86,15 +86,13 @@ public ArmOperation StartDelete(CancellationToken cancellationToken = public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) { var operation = await Operations.StartDeleteByIdAsync(Id, _apiVersion, cancellationToken).ConfigureAwait(false); - return new ArmVoidOperation(operation); + return new VoidArmOperation(operation); } /// public ArmResponse AddTag(string key, string value, CancellationToken cancellationToken = default) { GenericResource resource = GetResource(); - - // Potential optimization on tags set, remove NOOP to bypass the call. resource.Data.Tags[key] = value; return new PhArmResponse( Operations.StartUpdateById(Id, _apiVersion, resource.Data, cancellationToken).WaitForCompletionAsync(cancellationToken).EnsureCompleted(), diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs index 782049e856f9..fd799644ae3f 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs @@ -16,14 +16,14 @@ public interface IDeletableResource /// /// A token allowing immediate cancellation of any blocking call performed during the deletion. /// The status of the delete operation. - ArmResponse Delete(CancellationToken cancellationToken = default); + ArmResponse Delete(CancellationToken cancellationToken = default); /// /// Delete the resource. /// /// A token allowing immediate cancellation of any blocking call performed during the deletion. /// A that on completion returns the status of the delete operation. - Task> DeleteAsync(CancellationToken cancellationToken = default); + Task DeleteAsync(CancellationToken cancellationToken = default); /// /// Delete the resource. diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs similarity index 75% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index dcd49e489a6c..35d166888f62 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -8,11 +8,20 @@ namespace Azure.ResourceManager.Core { + /// + /// Abstract class for long-running or synchronous applications. + /// + public abstract class ArmOperation : ArmOperation, IOperationSource + { + } + /// /// Abstract class for long-running or synchronous applications. /// /// The to return representing the result of the ArmOperation. - public abstract class ArmOperation : Operation +#pragma warning disable SA1402 // File may only contain a single type + public abstract class ArmOperation : Operation, IOperationSource +#pragma warning restore SA1402 // File may only contain a single type { /// /// Initializes a new instance of the class for mocking. @@ -22,24 +31,26 @@ protected ArmOperation() } /// - /// Initializes a new instance of the class. + /// Gets or sets the SyncValue /// - /// The representing the result of the ArmOperation. - protected ArmOperation(TOperations syncValue) - { - CompletedSynchronously = syncValue != null; - SyncValue = syncValue; - } + protected TOperations SyncValue { get; set; } /// - /// Gets a value indicating whether or not the operation completed synchronously. + /// Gets or sets whether or not this is an LRO /// - protected bool CompletedSynchronously { get; } + protected bool IsLongRunningOperation { get; set; } - /// - /// Gets the representing the result of the ArmOperation. - /// - protected TOperations SyncValue { get; } + /// + public TOperations CreateResult(Response response, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + /// + public ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } /// /// Waits for the completion of the long running operations. @@ -65,7 +76,6 @@ public ArmResponse WaitForCompletion(CancellationToken cancellation /// public ArmResponse WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) { - var polling = TimeSpan.FromSeconds(pollingInterval); while (true) { UpdateStatus(cancellationToken); diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs new file mode 100644 index 000000000000..96ffbdbb9d99 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs @@ -0,0 +1,369 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable enable + +using System; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.ResourceManager.Core +{ + /// + /// This implements the ARM scenarios for LROs. It is highly recommended to read the ARM spec prior to modifying this code: + /// https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/Addendum.md#asynchronous-operations + /// Other reference documents include: + /// https://github.com/Azure/autorest/blob/master/docs/extensions/readme.md#x-ms-long-running-operation + /// https://github.com/Azure/adx-documentation-pr/blob/master/sdks/LRO/LRO_AzureSDK.md + /// + /// The final result of the LRO. + internal class ArmOperationHelpers + { + public static TimeSpan DefaultPollingInterval { get; } = TimeSpan.FromSeconds(1); + + private static readonly string[] s_failureStates = { "failed", "canceled" }; + private static readonly string[] s_terminalStates = { "succeeded", "failed", "canceled" }; + + private readonly HttpPipeline _pipeline; + private readonly ClientDiagnostics _clientDiagnostics; + private readonly string _scopeName; + private readonly RequestMethod _requestMethod; + private readonly Uri _originalUri; + private readonly OperationFinalStateVia _finalStateVia; + private HeaderFrom _headerFrom; + private string _pollUri = default!; + private bool _originalHasLocation; + private string? _lastKnownLocation; + + private readonly IOperationSource _source; + private Response _rawResponse; + private T _value = default!; + private bool _hasValue; + private bool _hasCompleted; + private bool _shouldPoll; + + public ArmOperationHelpers( + IOperationSource source, + ClientDiagnostics clientDiagnostics, + HttpPipeline pipeline, + Request originalRequest, + Response originalResponse, + OperationFinalStateVia finalStateVia, + string scopeName) + { + _source = source; + _rawResponse = originalResponse; + _requestMethod = originalRequest.Method; + _originalUri = originalRequest.Uri.ToUri(); + _finalStateVia = finalStateVia; + InitializeScenarioInfo(); + + _pipeline = pipeline; + _clientDiagnostics = clientDiagnostics; + _scopeName = scopeName; + // When the original response has no headers, we do not start polling immediately. + _shouldPoll = _headerFrom != HeaderFrom.None; + } + + public Response GetRawResponse() => _rawResponse; + + public ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + return WaitForCompletionAsync(DefaultPollingInterval, cancellationToken); + } + + public async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + { + while (true) + { + await UpdateStatusAsync(cancellationToken).ConfigureAwait(false); + if (HasCompleted) + { + return Response.FromValue(Value, GetRawResponse()); + } + + await Task.Delay(pollingInterval, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask UpdateStatusAsync(bool async, CancellationToken cancellationToken) + { + if (_hasCompleted) + { + return GetRawResponse(); + } + + if (_shouldPoll) + { + UpdatePollUri(); + _rawResponse = async + ? await GetResponseAsync(_pollUri, cancellationToken).ConfigureAwait(false) + : GetResponse(_pollUri, cancellationToken); + } + + _shouldPoll = true; + _hasCompleted = IsTerminalState(out string state); + if (_hasCompleted) + { + Response finalResponse = GetRawResponse(); + if (s_failureStates.Contains(state)) + { + throw _clientDiagnostics.CreateRequestFailedException(finalResponse); + } + + string? finalUri = GetFinalUri(); + if (finalUri != null) + { + finalResponse = async + ? await GetResponseAsync(finalUri, cancellationToken).ConfigureAwait(false) + : GetResponse(finalUri, cancellationToken); + } + + switch (finalResponse.Status) + { + case 200: + case 201 when _requestMethod == RequestMethod.Put: + case 204 when !(_requestMethod == RequestMethod.Put || _requestMethod == RequestMethod.Patch): + { + _value = async + ? await _source.CreateResultAsync(finalResponse, cancellationToken).ConfigureAwait(false) + : _source.CreateResult(finalResponse, cancellationToken); + _rawResponse = finalResponse; + _hasValue = true; + break; + } + default: + throw _clientDiagnostics.CreateRequestFailedException(finalResponse); + } + } + + return GetRawResponse(); + } + + public async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => await UpdateStatusAsync(async: true, cancellationToken).ConfigureAwait(false); + + public Response UpdateStatus(CancellationToken cancellationToken = default) => UpdateStatusAsync(async: false, cancellationToken).EnsureCompleted(); + +#pragma warning disable CA1822 + //TODO: This is currently unused. + public string Id => throw new NotImplementedException(); +#pragma warning restore CA1822 + + public T Value + { + get + { + if (!HasValue) + { + throw new InvalidOperationException("The operation has not completed yet."); + } + + return _value; + } + } + + public bool HasCompleted => _hasCompleted; + public bool HasValue => _hasValue; + + private HttpMessage CreateRequest(string link) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Get; + + if (Uri.TryCreate(link, UriKind.Absolute, out var nextLink) && nextLink.Scheme != "file") + { + request.Uri.Reset(nextLink); + } + else + { + request.Uri.Reset(new Uri(_originalUri, link)); + } + + return message; + } + + private async ValueTask GetResponseAsync(string link, CancellationToken cancellationToken = default) + { + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName); + scope.Start(); + try + { + using HttpMessage message = CreateRequest(link); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + return message.Response; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + private Response GetResponse(string link, CancellationToken cancellationToken = default) + { + if (link == null) + { + throw new ArgumentNullException(nameof(link)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName); + scope.Start(); + try + { + using HttpMessage message = CreateRequest(link); + _pipeline.Send(message, cancellationToken); + return message.Response; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + private bool IsTerminalState(out string state) + { + Response response = GetRawResponse(); + state = string.Empty; + if (_headerFrom == HeaderFrom.Location) + { + return response.Status != 202; + } + + if (response.Status >= 200 && response.Status <= 204) + { + if (response.ContentStream?.Length > 0) + { + try + { + using JsonDocument document = JsonDocument.Parse(response.ContentStream); + foreach (JsonProperty property in document.RootElement.EnumerateObject()) + { + if ((_headerFrom == HeaderFrom.OperationLocation || + _headerFrom == HeaderFrom.AzureAsyncOperation) && + property.NameEquals("status")) + { + state = property.Value.GetString().ToLowerInvariant(); + return s_terminalStates.Contains(state); + } + + if (_headerFrom == HeaderFrom.None && property.NameEquals("properties")) + { + foreach (JsonProperty innerProperty in property.Value.EnumerateObject()) + { + if (innerProperty.NameEquals("provisioningState")) + { + state = innerProperty.Value.GetString().ToLowerInvariant(); + return s_terminalStates.Contains(state); + } + } + } + } + } + finally + { + // It is required to reset the position of the content after reading as this response may be used for deserialization. + response.ContentStream.Position = 0; + } + } + + // If provisioningState was not found, it defaults to Succeeded. + if (_headerFrom == HeaderFrom.None) + { + return true; + } + } + + throw _clientDiagnostics.CreateRequestFailedException(response); + } + + private enum HeaderFrom + { + None, + OperationLocation, + AzureAsyncOperation, + Location + } + + private void InitializeScenarioInfo() + { + _originalHasLocation = _rawResponse.Headers.Contains("Location"); + + if (_rawResponse.Headers.Contains("Operation-Location")) + { + _headerFrom = HeaderFrom.OperationLocation; + return; + } + + if (_rawResponse.Headers.Contains("Azure-AsyncOperation")) + { + _headerFrom = HeaderFrom.AzureAsyncOperation; + return; + } + + if (_originalHasLocation) + { + _headerFrom = HeaderFrom.Location; + return; + } + + _pollUri = _originalUri.AbsoluteUri; + _headerFrom = HeaderFrom.None; + } + + private void UpdatePollUri() + { + var hasLocation = _rawResponse.Headers.TryGetValue("Location", out string? location); + if (hasLocation) + { + _lastKnownLocation = location; + } + + switch (_headerFrom) + { + case HeaderFrom.OperationLocation when _rawResponse.Headers.TryGetValue("Operation-Location", out string? operationLocation): + _pollUri = operationLocation; + return; + case HeaderFrom.AzureAsyncOperation when _rawResponse.Headers.TryGetValue("Azure-AsyncOperation", out string? azureAsyncOperation): + _pollUri = azureAsyncOperation; + return; + case HeaderFrom.Location when hasLocation: + _pollUri = location!; + return; + } + } + + private string? GetFinalUri() + { + if (_headerFrom == HeaderFrom.OperationLocation || _headerFrom == HeaderFrom.AzureAsyncOperation) + { + if (_requestMethod == RequestMethod.Delete) + { + return null; + } + + if (_requestMethod == RequestMethod.Put || (_originalHasLocation && _finalStateVia == OperationFinalStateVia.OriginalUri)) + { + return _originalUri.AbsoluteUri; + } + + if (_originalHasLocation && _finalStateVia == OperationFinalStateVia.Location) + { + return _lastKnownLocation; + } + } + + return null; + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs similarity index 99% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index 9f293c1d5364..33318392c2fe 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -33,7 +33,6 @@ protected PhArmOperation() /// The results to wrap. /// The function used to convert from existing type to new type. public PhArmOperation(Operation wrapped, Func converter) - : base(null) { _wrapped = wrapped; _converter = converter; diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs new file mode 100644 index 000000000000..0bc1cac82911 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; + +namespace Azure.ResourceManager.Core +{ + internal class ValueArmOperation : ArmOperation + { + public override string Id => throw new NotImplementedException(); + + public override TOperations Value => throw new NotImplementedException(); + + public override bool HasCompleted => throw new NotImplementedException(); + + public override bool HasValue => throw new NotImplementedException(); + + public override Response GetRawResponse() + { + throw new NotImplementedException(); + } + + public override Response UpdateStatus(CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs similarity index 85% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs index f0d24e3e714e..2a29a5f17b15 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ArmVoidOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs @@ -10,32 +10,31 @@ namespace Azure.ResourceManager.Core /// /// Generic ARM long running operation class for operations with no returned value /// - public sealed class ArmVoidOperation : ArmOperation + internal sealed class VoidArmOperation : ArmOperation { - private readonly Operation _wrapped; - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The operation that has a response which has no body. - public ArmVoidOperation(Operation other) - : base(null) + public VoidArmOperation(Operation other) { if (other is null) throw new ArgumentNullException(nameof(other)); _wrapped = other; + IsLongRunningOperation = true; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The response which has no body. - public ArmVoidOperation(Response other) - : base(other) + public VoidArmOperation(Response other) { if (other is null) throw new ArgumentNullException(nameof(other)); + + SyncValue = other; } /// @@ -45,10 +44,10 @@ public ArmVoidOperation(Response other) public override Response Value => SyncValue; /// - public override bool HasCompleted => CompletedSynchronously || _wrapped.HasCompleted; + public override bool HasCompleted => !IsLongRunningOperation || _wrapped.HasCompleted; /// - public override bool HasValue => CompletedSynchronously || _wrapped.HasValue; + public override bool HasValue => !IsLongRunningOperation || _wrapped.HasValue; /// public override Response GetRawResponse() diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs index d5057ad8fa90..c3c1a1627b53 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs @@ -70,15 +70,15 @@ protected ResourceGroupOperations(ResourceOperationsBase options, ResourceIdenti /// When you delete a resource group, all of its resources are also deleted. Deleting a resource group deletes all of its template deployments and currently stored operations. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - public virtual ArmResponse Delete(CancellationToken cancellationToken = default) + /// A response with the operation for this resource. + public virtual ArmResponse Delete(CancellationToken cancellationToken = default) { using var scope = Diagnostics.CreateScope("ResourceGroupOperations.Delete"); scope.Start(); try { - return new ArmResponse(Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletion(cancellationToken)); + return ArmResponse.FromResponse(Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletion(cancellationToken)); } catch (Exception e) { @@ -91,15 +91,15 @@ public virtual ArmResponse Delete(CancellationToken cancellationToken /// When you delete a resource group, all of its resources are also deleted. Deleting a resource group deletes all of its template deployments and currently stored operations. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A that on completion returns a response with the operation for this resource. - public virtual async Task> DeleteAsync(CancellationToken cancellationToken = default) + /// A that on completion returns a response with the operation for this resource. + public virtual async Task DeleteAsync(CancellationToken cancellationToken = default) { using var scope = Diagnostics.CreateScope("ResourceGroupOperations.Delete"); scope.Start(); try { - return new ArmResponse(await Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); + return ArmResponse.FromResponse(await Operations.StartDelete(Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); } catch (Exception e) { @@ -123,7 +123,7 @@ public virtual ArmOperation StartDelete(CancellationToken cancellation try { - return new ArmVoidOperation(Operations.StartDelete(Id.Name, cancellationToken)); + return new VoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken)); } catch (Exception e) { @@ -147,7 +147,7 @@ public virtual async Task> StartDeleteAsync(CancellationT try { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false)); + return new VoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false)); } catch (Exception e) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs new file mode 100644 index 000000000000..ebcfabfee872 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.ResourceManager.Core +{ + /// + /// A class representing a response object from azure resource manager service. + /// + public abstract class ArmResponse : Response + { + /// + /// Creates a new instance of with the provided value and HTTP response. + /// + /// The type of the value. + /// The value. + /// The HTTP response. + /// A new instance of with the provided value and HTTP response. + /// Throws if response or value are null. + public static ArmResponse FromValue(TOperations value, ArmResponse response) + { + if (value is null) + throw new ArgumentNullException(nameof(value)); + + if (response is null) + throw new ArgumentNullException(nameof(response)); + + return new ValueArmResponse(response, value); + } + + /// + /// Creates a new instance of with the provided value and HTTP response. + /// + /// The HTTP response. + /// A new instance of with the provided value and HTTP response. + /// Throws if response is null. + public static ArmResponse FromResponse(Response response) + { + if (response is null) + throw new ArgumentNullException(nameof(response)); + + return new VoidArmResponse(response); + } + } + + /// + /// A class representing a response object from azure resource manager service. + /// + /// The operations object return by the api call. + [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Allowed when we have a generic version of the same type")] + public abstract class ArmResponse : Response + { + /// + /// Returns the value of this object. + /// + /// The instance. + public static implicit operator TOperations(ArmResponse response) => response.Value; + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Adapters/PhArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/PhArmResponse.cs similarity index 100% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Adapters/PhArmResponse.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/PhArmResponse.cs diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs new file mode 100644 index 000000000000..ab8ff5d5b71e --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Azure.ResourceManager.Core +{ + internal class ValueArmResponse : ArmResponse + { + private readonly ArmResponse _response; + + public ValueArmResponse(ArmResponse response, TOperations value) + { + _response = response; + Value = value; + } + + public override TOperations Value { get; } + + public override Response GetRawResponse() => _response; + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs new file mode 100644 index 000000000000..2132289a559a --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.IO; +using Azure.Core; + +namespace Azure.ResourceManager.Core +{ + internal class VoidArmResponse : ArmResponse + { + private readonly Response _response; + + public VoidArmResponse(Response response) + { + _response = response; + } + + /// + public override int Status => _response.Status; + + /// + public override string ReasonPhrase => _response.ReasonPhrase; + + /// + public override Stream ContentStream + { + get => _response.ContentStream; + set => _response.ContentStream = value; + } + + /// + public override string ClientRequestId + { + get => _response.ClientRequestId; + set => _response.ClientRequestId = value; + } + + /// + public override void Dispose() => _response.Dispose(); + + /// + protected override bool ContainsHeader(string name) => _response.Headers.Contains(name); + + /// + protected override IEnumerable EnumerateHeaders() => _response.Headers; + + /// + protected override bool TryGetHeader(string name, out string value) => _response.Headers.TryGetValue(name, out value); + + /// + protected override bool TryGetHeaderValues(string name, out IEnumerable values) => _response.Headers.TryGetValues(name, out values); + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs new file mode 100644 index 000000000000..b522100cb0e5 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.ResourceManager.Core +{ + internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource + { + public UpdateResourceGroupOperation() + { + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs index 06e502e0ed5f..868671e7a9c3 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ArmResponseTests.cs @@ -12,8 +12,7 @@ public class ArmResponseTests [TestCase] public void TestArmResponseParamCheck() { - Assert.Throws(() => { new ArmResponse(null); }); - + Assert.Throws(() => { ArmResponse.FromResponse(null); }); } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs index 208c970bf67b..a042dd2bc58b 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs @@ -13,8 +13,8 @@ public class ResourceTypeFilterTests [TestCase] public void TestResourceTypeFilterParamCheck() { - Assert.Throws(() => { new ArmVoidOperation((Operation)null); }); - Assert.Throws(() => { new ArmVoidOperation((Response)null); }); + Assert.Throws(() => { new VoidArmOperation((Operation)null); }); + Assert.Throws(() => { new VoidArmOperation((Response)null); }); } } } From 0f52a38b28a28b150d2379add7062ade03b0d8c1 Mon Sep 17 00:00:00 2001 From: m-nash <64171366+m-nash@users.noreply.github.com> Date: Wed, 24 Mar 2021 15:32:01 -0700 Subject: [PATCH 02/15] wip --- .../src/Operation/ArmOperation.cs | 62 ++++++++-- .../src/Operation/PhArmOperation.cs | 16 ++- .../src/Operation/ValueArmOperation.cs | 15 +-- .../src/Placeholder/ResourceGroupData.cs | 2 +- .../ResourceGroupData.Serialization.cs | 111 ++++++++++++++++++ .../src/UpdateResourceGroupOperation.cs | 15 +++ 6 files changed, 191 insertions(+), 30 deletions(-) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index 35d166888f62..062c123c82a4 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -5,13 +5,14 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core; +using Azure.Core.Pipeline; namespace Azure.ResourceManager.Core { /// /// Abstract class for long-running or synchronous applications. /// - public abstract class ArmOperation : ArmOperation, IOperationSource + public abstract class ArmOperation : ArmOperation { } @@ -20,9 +21,12 @@ public abstract class ArmOperation : ArmOperation, IOperationSource /// The to return representing the result of the ArmOperation. #pragma warning disable SA1402 // File may only contain a single type - public abstract class ArmOperation : Operation, IOperationSource + public abstract class ArmOperation : Operation + where TOperations : notnull, IUtf8JsonSerializable #pragma warning restore SA1402 // File may only contain a single type { + private readonly ArmOperationHelpers _operation; + /// /// Initializes a new instance of the class for mocking. /// @@ -31,27 +35,63 @@ protected ArmOperation() } /// - /// Gets or sets the SyncValue + /// /// - protected TOperations SyncValue { get; set; } + /// + protected ArmOperation(Operation operation) + { + WrappedOperation = operation; + } /// - /// Gets or sets whether or not this is an LRO + /// /// - protected bool IsLongRunningOperation { get; set; } + /// + protected ArmOperation(Response response) + { + WrappedResponse = response; + } - /// - public TOperations CreateResult(Response response, CancellationToken cancellationToken) + /// + /// + /// + /// + /// + /// + /// + protected ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response) { - throw new NotImplementedException(); + _operation = new ArmOperationHelpers(this, ) } + /// + /// + /// + protected Response WrappedResponse { get; private set; } + + /// + /// + /// + protected Operation WrappedOperation { get; private set; } + /// - public ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + public override TOperations Value => WrappedOperation is null ? WrappedResponse.Value : WrappedOperation.Value; + + /// + public override bool HasCompleted => WrappedResponse is null ? WrappedOperation.HasCompleted : true; + + /// + public override bool HasValue => WrappedResponse is null ? WrappedOperation.HasValue : true; + + /// + public override Response GetRawResponse() { - throw new NotImplementedException(); + return WrappedResponse is null ? WrappedOperation.GetRawResponse() : WrappedResponse.GetRawResponse(); } + /// + public override string Id => WrappedOperation?.Id; + /// /// Waits for the completion of the long running operations. /// diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index 33318392c2fe..f57461e7dd77 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -17,8 +17,7 @@ public class PhArmOperation : ArmOperation where TModel : class { private readonly Func _converter; - private readonly Response _syncWrapped; - private readonly Operation _wrapped; + private readonly ArmOperation _wrapped; /// /// Initializes a new instance of the class for mocking. @@ -34,7 +33,7 @@ protected PhArmOperation() /// The function used to convert from existing type to new type. public PhArmOperation(Operation wrapped, Func converter) { - _wrapped = wrapped; + _wrapped = new ValueArmOperation(wrapped); _converter = converter; } @@ -44,23 +43,22 @@ public PhArmOperation(Operation wrapped, Func conve /// The results to wrap. /// The function used to convert from existing type to new type. public PhArmOperation(Response wrapped, Func converter) - : base(converter(wrapped.Value)) { + _wrapped = new ValueArmOperation(wrapped); _converter = converter; - _syncWrapped = wrapped; } /// - public override string Id => _wrapped?.Id; + public override string Id => _wrapped.Id; /// - public override TOperations Value => CompletedSynchronously ? SyncValue : _converter(_wrapped.Value); + public override TOperations Value => _converter(_wrapped.Value); /// - public override bool HasCompleted => CompletedSynchronously || _wrapped.HasCompleted; + public override bool HasCompleted => _wrapped.HasCompleted; /// - public override bool HasValue => CompletedSynchronously || _wrapped.HasValue; + public override bool HasValue => _wrapped.HasValue; /// public override Response GetRawResponse() diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs index 0bc1cac82911..f418faad7a1d 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs @@ -12,17 +12,14 @@ namespace Azure.ResourceManager.Core { internal class ValueArmOperation : ArmOperation { - public override string Id => throw new NotImplementedException(); - - public override TOperations Value => throw new NotImplementedException(); - - public override bool HasCompleted => throw new NotImplementedException(); - - public override bool HasValue => throw new NotImplementedException(); + internal ValueArmOperation(Operation operation) + :base(operation) + { + } - public override Response GetRawResponse() + internal ValueArmOperation(Response operation) + : base(operation) { - throw new NotImplementedException(); } public override Response UpdateStatus(CancellationToken cancellationToken = default) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs index 175310efcb45..39615f9d399a 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Placeholder/ResourceGroupData.cs @@ -10,7 +10,7 @@ namespace Azure.ResourceManager.Core /// /// A class representing the ResourceGroup data model. /// - public class ResourceGroupData : TrackedResource + public partial class ResourceGroupData : TrackedResource { /// /// Initializes a new instance of the class. diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs new file mode 100644 index 000000000000..d430f210e2c1 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; +using Azure.ResourceManager.Resources.Models; + +namespace Azure.ResourceManager.Core +{ + public partial class ResourceGroupData : TrackedResource, IUtf8JsonSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + if (Optional.IsDefined(Properties)) + { + writer.WritePropertyName("properties"); + writer.WriteObjectValue(Properties); + } + writer.WritePropertyName("location"); + writer.WriteStringValue(Location); + if (Optional.IsDefined(ManagedBy)) + { + writer.WritePropertyName("managedBy"); + writer.WriteStringValue(ManagedBy); + } + if (Optional.IsCollectionDefined(Tags)) + { + writer.WritePropertyName("tags"); + writer.WriteStartObject(); + foreach (var item in Tags) + { + writer.WritePropertyName(item.Key); + writer.WriteStringValue(item.Value); + } + writer.WriteEndObject(); + } + writer.WriteEndObject(); + } + + internal static ResourceGroup DeserializeResourceGroup(JsonElement element) + { + Optional id = default; + Optional name = default; + Optional type = default; + Optional properties = default; + string location = default; + Optional managedBy = default; + Optional> tags = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("id")) + { + id = property.Value.GetString(); + continue; + } + if (property.NameEquals("name")) + { + name = property.Value.GetString(); + continue; + } + if (property.NameEquals("type")) + { + type = property.Value.GetString(); + continue; + } + if (property.NameEquals("properties")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + property.ThrowNonNullablePropertyIsNull(); + continue; + } + properties = ResourceGroupProperties.DeserializeResourceGroupProperties(property.Value); + continue; + } + if (property.NameEquals("location")) + { + location = property.Value.GetString(); + continue; + } + if (property.NameEquals("managedBy")) + { + managedBy = property.Value.GetString(); + continue; + } + if (property.NameEquals("tags")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + property.ThrowNonNullablePropertyIsNull(); + continue; + } + Dictionary dictionary = new Dictionary(); + foreach (var property0 in property.Value.EnumerateObject()) + { + dictionary.Add(property0.Name, property0.Value.GetString()); + } + tags = dictionary; + continue; + } + } + return new ResourceGroupData(new Azure.ResourceManager.Resources.Models.ResourceGroup(id.Value, name.Value, type.Value, properties.Value, location, managedBy.Value, Optional.ToDictionary(tags))); + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs index b522100cb0e5..be85a7c39829 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -13,8 +14,22 @@ namespace Azure.ResourceManager.Core { internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource { + private readonly ArmOperationHelpers _operation; + public UpdateResourceGroupOperation() { } + + ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) + { + using var document = JsonDocument.Parse(response.ContentStream); + return ResourceGroup.DeserializeGalleryImage(document.RootElement); + } + + async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + return ResourceGroup.DeserializeGalleryImage(document.RootElement); + } } } From 10f6ad0c6416ee7b84427b30a3068fec2005e6aa Mon Sep 17 00:00:00 2001 From: YalinLi0312 Date: Wed, 24 Mar 2021 16:18:02 -0700 Subject: [PATCH 03/15] Change the accessbility to virtual for Resource.Id --- .../Azure.ResourceManager.Core/src/Resources/Resource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs index 86a35ac05cf7..a8638d1c689b 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/Resource.cs @@ -14,7 +14,7 @@ public abstract class Resource : IEquatable, IEquatable, IComp /// /// Gets or sets the resource identifier. /// - public abstract ResourceIdentifier Id { get; protected set; } + public virtual ResourceIdentifier Id { get; protected set; } /// /// Gets the name. From c192698cae8165780a38f5aa7852164de3dd341e Mon Sep 17 00:00:00 2001 From: m-nash Date: Wed, 31 Mar 2021 20:55:31 -0700 Subject: [PATCH 04/15] update strawman for operation changes --- .../src/GenericResourceOperations.cs | 10 +- .../src/IDeletableResource.cs | 4 +- .../UpdateResourceGroupOperation.cs | 51 +++ .../src/Operation/ArmOperation.cs | 212 ++++++++-- .../src/Operation/ArmOperationHelpers.cs | 369 ------------------ .../src/Operation/PhArmOperation.cs | 73 ++-- .../src/Operation/PhVoidArmOperation.cs | 113 ++++++ .../src/Operation/ValueArmOperation.cs | 32 -- .../src/Operation/VoidArmOperation.cs | 101 +---- .../src/ResourceGroupContainer.cs | 4 +- .../src/ResourceGroupOperations.cs | 8 +- .../ResourceGroupData.Serialization.cs | 111 ------ .../src/UpdateResourceGroupOperation.cs | 35 -- .../tests/Unit/ResourceTypeFilterTests.cs | 1 - 14 files changed, 402 insertions(+), 722 deletions(-) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs index e53570b8f9ae..b01c039d80cf 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/GenericResourceOperations.cs @@ -77,9 +77,9 @@ public async Task DeleteAsync(CancellationToken cancellationToken = /// /// Details on long running operation object. /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new VoidArmOperation(Operations.StartDeleteById(Id, GetApiVersion(cancellationToken), cancellationToken)); + return new PhVoidArmOperation(Operations.StartDeleteById(Id, GetApiVersion(cancellationToken), cancellationToken)); } /// @@ -93,10 +93,10 @@ public ArmOperation StartDelete(CancellationToken cancellationToken = /// /// Details on long running operation object. /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { var operation = await Operations.StartDeleteByIdAsync(Id, await GetApiVersionAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); - return new VoidArmOperation(operation); + return new PhVoidArmOperation(operation); } /// @@ -126,7 +126,7 @@ public ArmOperation StartAddTag(string key, string value, Cance GenericResource resource = GetResource(); resource.Data.Tags[key] = value; return new PhArmOperation( - Operations.StartUpdateById(Id, GetApiVersion(cancellationToken), resource.Data, cancellationToken).WaitForCompletionAsync(cancellationToken).EnsureCompleted(), + Operations.StartUpdateById(Id, GetApiVersion(cancellationToken), resource.Data, cancellationToken), v => new GenericResource(this, new GenericResourceData(v))); } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs index fd799644ae3f..f77a93d5dedf 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/IDeletableResource.cs @@ -34,7 +34,7 @@ public interface IDeletableResource /// /// Details on long running operation object. /// - ArmOperation StartDelete(CancellationToken cancellationToken = default); + ArmOperation StartDelete(CancellationToken cancellationToken = default); /// /// Delete the resource. This call returns a Task that blocks until the delete operation is accepted on the service. @@ -47,6 +47,6 @@ public interface IDeletableResource /// /// Details on long running operation object. /// - Task> StartDeleteAsync(CancellationToken cancellationToken = default); + Task StartDeleteAsync(CancellationToken cancellationToken = default); } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs new file mode 100644 index 000000000000..12b58c4a8966 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; + +namespace Azure.ResourceManager.Core +{ + internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource + { + private readonly ResourceOperationsBase _operations; + + protected UpdateResourceGroupOperation() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The operation source to use. + /// The arm operations object to copy from. + /// The original request. + /// The original response. + internal UpdateResourceGroupOperation(IOperationSource source, ResourceOperationsBase operations, Request request, Response response) + : base(source, operations.Diagnostics, ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), request, response, "UpdateResourceGroupOperation") + { + _operations = operations; + } + + ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) + { + using var document = JsonDocument.Parse(response.ContentStream); + return GetResourceGrouop(document); + } + + private ResourceGroup GetResourceGrouop(JsonDocument document) + { + var method = typeof(ResourceManager.Resources.Models.ResourceGroup).GetMethod("DeserializeResourceGroup", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); + var obj = method.Invoke(null, new object[] { document.RootElement }); + return new ResourceGroup(_operations, new ResourceGroupData(obj as ResourceManager.Resources.Models.ResourceGroup)); + } + + async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + return GetResourceGrouop(document); + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index 062c123c82a4..91029ec2b479 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -12,8 +12,128 @@ namespace Azure.ResourceManager.Core /// /// Abstract class for long-running or synchronous applications. /// - public abstract class ArmOperation : ArmOperation + public abstract class ArmOperation : Operation { + private readonly ArmOperationHelpers _operation; + private readonly Response _voidResponse; + + /// + /// Initializes a new instance of the class for mocking. + /// + protected ArmOperation() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The operation source to use. + /// The client diagnostics to use. + /// The HttpPipeline to use. + /// The original request. + /// The original response. + /// The scope name to use. + internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName) + { + _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName); + } + + /// + /// Initializes a new instance of the class. + /// + /// + protected ArmOperation(Response response) + { + if (response is null) + throw new ArgumentNullException(nameof(response)); + + _voidResponse = response; + } + + /// + private bool _doesWrapOperation => _voidResponse is null; + + /// + public override string Id => _operation?.Id; + + /// + public override Response Value => throw new InvalidOperationException(); + + /// + public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true; + + /// + public override bool HasValue => false; + + /// + public override Response GetRawResponse() + { + return _doesWrapOperation ? _operation.GetRawResponse() : _voidResponse; + } + + /// + public override Response UpdateStatus(CancellationToken cancellationToken = default) + { + return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _voidResponse; + } + + /// + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + { + return _doesWrapOperation + ? _operation.UpdateStatusAsync(cancellationToken) + : new ValueTask(_voidResponse); + } + + /// + public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); + } + + /// + public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + { + return _doesWrapOperation + ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) + : Response.FromValue(_voidResponse, _voidResponse); + } + + /// + /// Waits for the completion of the long running operations. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + /// + /// Details on long running operation object. + /// + public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) + { + return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + } + + /// + /// Waits for the completion of the long running operations. + /// + /// The polling interval in seconds to check for status. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + /// + /// Details on long running operation object. + /// + public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + { + while (true) + { + UpdateStatus(cancellationToken); + if (HasCompleted) + { + return new VoidArmResponse(GetRawResponse()); + } + + Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); + } + } } /// @@ -22,10 +142,11 @@ public abstract class ArmOperation : ArmOperation /// The to return representing the result of the ArmOperation. #pragma warning disable SA1402 // File may only contain a single type public abstract class ArmOperation : Operation - where TOperations : notnull, IUtf8JsonSerializable + where TOperations : notnull #pragma warning restore SA1402 // File may only contain a single type { private readonly ArmOperationHelpers _operation; + private readonly Response _valueResponse; /// /// Initializes a new instance of the class for mocking. @@ -35,62 +156,81 @@ protected ArmOperation() } /// - /// + /// Initializes a new instance of the class. /// - /// - protected ArmOperation(Operation operation) - { - WrappedOperation = operation; - } - - /// - /// - /// - /// + /// The non lro response to wrap. protected ArmOperation(Response response) { - WrappedResponse = response; + if (response is null) + throw new ArgumentNullException(nameof(response)); + + _valueResponse = response; } /// - /// + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - protected ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response) + /// The operation source to use. + /// The client diagnostics to use. + /// The HttpPipeline to use. + /// The original request. + /// The original response. + /// The scope name to use. + internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName) { - _operation = new ArmOperationHelpers(this, ) + _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName); } - /// - /// - /// - protected Response WrappedResponse { get; private set; } + private bool _doesWrapOperation => _valueResponse is null; - /// - /// - /// - protected Operation WrappedOperation { get; private set; } + /// + public override string Id => _operation?.Id; /// - public override TOperations Value => WrappedOperation is null ? WrappedResponse.Value : WrappedOperation.Value; + public override TOperations Value => _doesWrapOperation ? _operation.Value : _valueResponse.Value; /// - public override bool HasCompleted => WrappedResponse is null ? WrappedOperation.HasCompleted : true; + public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true; /// - public override bool HasValue => WrappedResponse is null ? WrappedOperation.HasValue : true; + public override bool HasValue => _doesWrapOperation ? _operation.HasValue : true; /// public override Response GetRawResponse() { - return WrappedResponse is null ? WrappedOperation.GetRawResponse() : WrappedResponse.GetRawResponse(); + return _doesWrapOperation ? _operation.GetRawResponse() : _valueResponse.GetRawResponse(); } /// - public override string Id => WrappedOperation?.Id; + public override Response UpdateStatus(CancellationToken cancellationToken = default) + { + return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _valueResponse.GetRawResponse(); + } + + /// + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + { + return _doesWrapOperation + ? _operation.UpdateStatusAsync(cancellationToken) + : new ValueTask(_valueResponse.GetRawResponse()); + } + + /// + public override async ValueTask> WaitForCompletionAsync( + CancellationToken cancellationToken = default) + { + return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); + } + + /// + public override async ValueTask> WaitForCompletionAsync( + TimeSpan pollingInterval, + CancellationToken cancellationToken) + { + return _doesWrapOperation + ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) + : _valueResponse; + } /// /// Waits for the completion of the long running operations. @@ -100,7 +240,7 @@ public override Response GetRawResponse() /// /// Details on long running operation object. /// - public ArmResponse WaitForCompletion(CancellationToken cancellationToken = default) + public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) { return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); } @@ -114,7 +254,7 @@ public ArmResponse WaitForCompletion(CancellationToken cancellation /// /// Details on long running operation object. /// - public ArmResponse WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) { while (true) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs deleted file mode 100644 index 96ffbdbb9d99..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperationHelpers.cs +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#nullable enable - -using System; -using System.Linq; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Azure.Core; -using Azure.Core.Pipeline; - -namespace Azure.ResourceManager.Core -{ - /// - /// This implements the ARM scenarios for LROs. It is highly recommended to read the ARM spec prior to modifying this code: - /// https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/Addendum.md#asynchronous-operations - /// Other reference documents include: - /// https://github.com/Azure/autorest/blob/master/docs/extensions/readme.md#x-ms-long-running-operation - /// https://github.com/Azure/adx-documentation-pr/blob/master/sdks/LRO/LRO_AzureSDK.md - /// - /// The final result of the LRO. - internal class ArmOperationHelpers - { - public static TimeSpan DefaultPollingInterval { get; } = TimeSpan.FromSeconds(1); - - private static readonly string[] s_failureStates = { "failed", "canceled" }; - private static readonly string[] s_terminalStates = { "succeeded", "failed", "canceled" }; - - private readonly HttpPipeline _pipeline; - private readonly ClientDiagnostics _clientDiagnostics; - private readonly string _scopeName; - private readonly RequestMethod _requestMethod; - private readonly Uri _originalUri; - private readonly OperationFinalStateVia _finalStateVia; - private HeaderFrom _headerFrom; - private string _pollUri = default!; - private bool _originalHasLocation; - private string? _lastKnownLocation; - - private readonly IOperationSource _source; - private Response _rawResponse; - private T _value = default!; - private bool _hasValue; - private bool _hasCompleted; - private bool _shouldPoll; - - public ArmOperationHelpers( - IOperationSource source, - ClientDiagnostics clientDiagnostics, - HttpPipeline pipeline, - Request originalRequest, - Response originalResponse, - OperationFinalStateVia finalStateVia, - string scopeName) - { - _source = source; - _rawResponse = originalResponse; - _requestMethod = originalRequest.Method; - _originalUri = originalRequest.Uri.ToUri(); - _finalStateVia = finalStateVia; - InitializeScenarioInfo(); - - _pipeline = pipeline; - _clientDiagnostics = clientDiagnostics; - _scopeName = scopeName; - // When the original response has no headers, we do not start polling immediately. - _shouldPoll = _headerFrom != HeaderFrom.None; - } - - public Response GetRawResponse() => _rawResponse; - - public ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - return WaitForCompletionAsync(DefaultPollingInterval, cancellationToken); - } - - public async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) - { - while (true) - { - await UpdateStatusAsync(cancellationToken).ConfigureAwait(false); - if (HasCompleted) - { - return Response.FromValue(Value, GetRawResponse()); - } - - await Task.Delay(pollingInterval, cancellationToken).ConfigureAwait(false); - } - } - - private async ValueTask UpdateStatusAsync(bool async, CancellationToken cancellationToken) - { - if (_hasCompleted) - { - return GetRawResponse(); - } - - if (_shouldPoll) - { - UpdatePollUri(); - _rawResponse = async - ? await GetResponseAsync(_pollUri, cancellationToken).ConfigureAwait(false) - : GetResponse(_pollUri, cancellationToken); - } - - _shouldPoll = true; - _hasCompleted = IsTerminalState(out string state); - if (_hasCompleted) - { - Response finalResponse = GetRawResponse(); - if (s_failureStates.Contains(state)) - { - throw _clientDiagnostics.CreateRequestFailedException(finalResponse); - } - - string? finalUri = GetFinalUri(); - if (finalUri != null) - { - finalResponse = async - ? await GetResponseAsync(finalUri, cancellationToken).ConfigureAwait(false) - : GetResponse(finalUri, cancellationToken); - } - - switch (finalResponse.Status) - { - case 200: - case 201 when _requestMethod == RequestMethod.Put: - case 204 when !(_requestMethod == RequestMethod.Put || _requestMethod == RequestMethod.Patch): - { - _value = async - ? await _source.CreateResultAsync(finalResponse, cancellationToken).ConfigureAwait(false) - : _source.CreateResult(finalResponse, cancellationToken); - _rawResponse = finalResponse; - _hasValue = true; - break; - } - default: - throw _clientDiagnostics.CreateRequestFailedException(finalResponse); - } - } - - return GetRawResponse(); - } - - public async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => await UpdateStatusAsync(async: true, cancellationToken).ConfigureAwait(false); - - public Response UpdateStatus(CancellationToken cancellationToken = default) => UpdateStatusAsync(async: false, cancellationToken).EnsureCompleted(); - -#pragma warning disable CA1822 - //TODO: This is currently unused. - public string Id => throw new NotImplementedException(); -#pragma warning restore CA1822 - - public T Value - { - get - { - if (!HasValue) - { - throw new InvalidOperationException("The operation has not completed yet."); - } - - return _value; - } - } - - public bool HasCompleted => _hasCompleted; - public bool HasValue => _hasValue; - - private HttpMessage CreateRequest(string link) - { - HttpMessage message = _pipeline.CreateMessage(); - Request request = message.Request; - request.Method = RequestMethod.Get; - - if (Uri.TryCreate(link, UriKind.Absolute, out var nextLink) && nextLink.Scheme != "file") - { - request.Uri.Reset(nextLink); - } - else - { - request.Uri.Reset(new Uri(_originalUri, link)); - } - - return message; - } - - private async ValueTask GetResponseAsync(string link, CancellationToken cancellationToken = default) - { - if (link == null) - { - throw new ArgumentNullException(nameof(link)); - } - - using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName); - scope.Start(); - try - { - using HttpMessage message = CreateRequest(link); - await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); - return message.Response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } - } - - private Response GetResponse(string link, CancellationToken cancellationToken = default) - { - if (link == null) - { - throw new ArgumentNullException(nameof(link)); - } - - using DiagnosticScope scope = _clientDiagnostics.CreateScope(_scopeName); - scope.Start(); - try - { - using HttpMessage message = CreateRequest(link); - _pipeline.Send(message, cancellationToken); - return message.Response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } - } - - private bool IsTerminalState(out string state) - { - Response response = GetRawResponse(); - state = string.Empty; - if (_headerFrom == HeaderFrom.Location) - { - return response.Status != 202; - } - - if (response.Status >= 200 && response.Status <= 204) - { - if (response.ContentStream?.Length > 0) - { - try - { - using JsonDocument document = JsonDocument.Parse(response.ContentStream); - foreach (JsonProperty property in document.RootElement.EnumerateObject()) - { - if ((_headerFrom == HeaderFrom.OperationLocation || - _headerFrom == HeaderFrom.AzureAsyncOperation) && - property.NameEquals("status")) - { - state = property.Value.GetString().ToLowerInvariant(); - return s_terminalStates.Contains(state); - } - - if (_headerFrom == HeaderFrom.None && property.NameEquals("properties")) - { - foreach (JsonProperty innerProperty in property.Value.EnumerateObject()) - { - if (innerProperty.NameEquals("provisioningState")) - { - state = innerProperty.Value.GetString().ToLowerInvariant(); - return s_terminalStates.Contains(state); - } - } - } - } - } - finally - { - // It is required to reset the position of the content after reading as this response may be used for deserialization. - response.ContentStream.Position = 0; - } - } - - // If provisioningState was not found, it defaults to Succeeded. - if (_headerFrom == HeaderFrom.None) - { - return true; - } - } - - throw _clientDiagnostics.CreateRequestFailedException(response); - } - - private enum HeaderFrom - { - None, - OperationLocation, - AzureAsyncOperation, - Location - } - - private void InitializeScenarioInfo() - { - _originalHasLocation = _rawResponse.Headers.Contains("Location"); - - if (_rawResponse.Headers.Contains("Operation-Location")) - { - _headerFrom = HeaderFrom.OperationLocation; - return; - } - - if (_rawResponse.Headers.Contains("Azure-AsyncOperation")) - { - _headerFrom = HeaderFrom.AzureAsyncOperation; - return; - } - - if (_originalHasLocation) - { - _headerFrom = HeaderFrom.Location; - return; - } - - _pollUri = _originalUri.AbsoluteUri; - _headerFrom = HeaderFrom.None; - } - - private void UpdatePollUri() - { - var hasLocation = _rawResponse.Headers.TryGetValue("Location", out string? location); - if (hasLocation) - { - _lastKnownLocation = location; - } - - switch (_headerFrom) - { - case HeaderFrom.OperationLocation when _rawResponse.Headers.TryGetValue("Operation-Location", out string? operationLocation): - _pollUri = operationLocation; - return; - case HeaderFrom.AzureAsyncOperation when _rawResponse.Headers.TryGetValue("Azure-AsyncOperation", out string? azureAsyncOperation): - _pollUri = azureAsyncOperation; - return; - case HeaderFrom.Location when hasLocation: - _pollUri = location!; - return; - } - } - - private string? GetFinalUri() - { - if (_headerFrom == HeaderFrom.OperationLocation || _headerFrom == HeaderFrom.AzureAsyncOperation) - { - if (_requestMethod == RequestMethod.Delete) - { - return null; - } - - if (_requestMethod == RequestMethod.Put || (_originalHasLocation && _finalStateVia == OperationFinalStateVia.OriginalUri)) - { - return _originalUri.AbsoluteUri; - } - - if (_originalHasLocation && _finalStateVia == OperationFinalStateVia.Location) - { - return _lastKnownLocation; - } - } - - return null; - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index f57461e7dd77..df48e26e9ecd 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Azure.Core; namespace Azure.ResourceManager.Core { @@ -17,7 +18,8 @@ public class PhArmOperation : ArmOperation where TModel : class { private readonly Func _converter; - private readonly ArmOperation _wrapped; + private readonly Operation _wrappedOperation; + private readonly ArmOperation _wrappedResponseOperation; /// /// Initializes a new instance of the class for mocking. @@ -33,7 +35,7 @@ protected PhArmOperation() /// The function used to convert from existing type to new type. public PhArmOperation(Operation wrapped, Func converter) { - _wrapped = new ValueArmOperation(wrapped); + _wrappedOperation = wrapped; _converter = converter; } @@ -44,63 +46,80 @@ public PhArmOperation(Operation wrapped, Func conve /// The function used to convert from existing type to new type. public PhArmOperation(Response wrapped, Func converter) { - _wrapped = new ValueArmOperation(wrapped); + _wrappedResponseOperation = new ValueArmOperation(wrapped); _converter = converter; } + private bool _doesWrapOperation => _wrappedResponseOperation is null; + /// - public override string Id => _wrapped.Id; + public override string Id => _wrappedOperation?.Id; /// - public override TOperations Value => _converter(_wrapped.Value); + public override TOperations Value => _converter(_doesWrapOperation ? _wrappedOperation.Value : _wrappedResponseOperation.Value); /// - public override bool HasCompleted => _wrapped.HasCompleted; + public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted; /// - public override bool HasValue => _wrapped.HasValue; + public override bool HasValue => _doesWrapOperation ? _wrappedOperation.HasValue : _wrappedResponseOperation.HasValue; /// public override Response GetRawResponse() { - return CompletedSynchronously ? _syncWrapped.GetRawResponse() : _wrapped.GetRawResponse(); + return _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse(); } /// public override Response UpdateStatus(CancellationToken cancellationToken = default) { - return CompletedSynchronously ? _syncWrapped.GetRawResponse() : _wrapped.UpdateStatus(cancellationToken); + return _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken); } /// public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) { - return CompletedSynchronously - ? new ValueTask(_syncWrapped.GetRawResponse()) - : _wrapped.UpdateStatusAsync(cancellationToken); + return _doesWrapOperation + ? _wrappedOperation.UpdateStatusAsync(cancellationToken) + : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken); + } + + /// + public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + var task = WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken); + return await task.ConfigureAwait(false); } /// - public override async ValueTask> WaitForCompletionAsync( - CancellationToken cancellationToken = default) + public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) { - return CompletedSynchronously - ? new PhArmResponse(_syncWrapped, _converter) - : new PhArmResponse( - await _wrapped.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false), - _converter); + var task = _doesWrapOperation + ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken) + : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken); + var value = await task.ConfigureAwait(false); + return Response.FromValue(_converter(value), GetRawResponse()); } /// - public override async ValueTask> WaitForCompletionAsync( - TimeSpan pollingInterval, - CancellationToken cancellationToken) + public override Response WaitForCompletion(CancellationToken cancellationToken = default) { - return CompletedSynchronously - ? new PhArmResponse(_syncWrapped, _converter) - : new PhArmResponse( - await _wrapped.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), - _converter); + return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + } + + /// + public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + { + while (true) + { + UpdateStatus(cancellationToken); + if (HasCompleted) + { + return Response.FromValue(Value, GetRawResponse()) as ArmResponse; + } + + Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); + } } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs new file mode 100644 index 000000000000..2c94407f519b --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; + +namespace Azure.ResourceManager.Core +{ + /// + /// A calss representing an arm operation wrapper object. + /// + public class PhVoidArmOperation : ArmOperation + { + private readonly Operation _wrappedOperation; + private readonly ArmOperation _wrappedResponseOperation; + + /// + /// Initializes a new instance of the class for mocking. + /// + protected PhVoidArmOperation() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The results to wrap. + public PhVoidArmOperation(Operation wrapped) + { + _wrappedOperation = wrapped; + } + + /// + /// Initializes a new instance of the class. + /// + /// The results to wrap. + public PhVoidArmOperation(Response wrapped) + { + _wrappedResponseOperation = new VoidArmOperation(wrapped); + } + + private bool _doesWrapOperation => _wrappedResponseOperation is null; + + /// + public override string Id => _wrappedOperation?.Id; + + /// + public override Response Value => throw new InvalidOperationException(); + + /// + public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted; + + /// + public override bool HasValue => false; + + /// + public override Response GetRawResponse() + { + return _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse(); + } + + /// + public override Response UpdateStatus(CancellationToken cancellationToken = default) + { + return _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken); + } + + /// + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + { + return _doesWrapOperation + ? _wrappedOperation.UpdateStatusAsync(cancellationToken) + : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken); + } + + /// + public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); + } + + /// + public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + { + return _doesWrapOperation + ? Response.FromValue(await _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse()) + : Response.FromValue(await _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse()); + } + + /// + public override Response WaitForCompletion(CancellationToken cancellationToken = default) + { + return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + } + + /// + public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + { + while (true) + { + UpdateStatus(cancellationToken); + if (HasCompleted) + { + return Response.FromValue(Value, GetRawResponse()); + } + + Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); + } + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs index f418faad7a1d..e546235de64d 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs @@ -1,45 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Azure.Core; - namespace Azure.ResourceManager.Core { internal class ValueArmOperation : ArmOperation { - internal ValueArmOperation(Operation operation) - :base(operation) - { - } - internal ValueArmOperation(Response operation) : base(operation) { } - - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs index 2a29a5f17b15..07f2d6679f3f 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs @@ -1,10 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Threading; -using System.Threading.Tasks; - namespace Azure.ResourceManager.Core { /// @@ -15,101 +11,10 @@ internal sealed class VoidArmOperation : ArmOperation /// /// Initializes a new instance of the class. /// - /// The operation that has a response which has no body. - public VoidArmOperation(Operation other) - { - if (other is null) - throw new ArgumentNullException(nameof(other)); - - _wrapped = other; - IsLongRunningOperation = true; - } - - /// - /// Initializes a new instance of the class. - /// - /// The response which has no body. - public VoidArmOperation(Response other) - { - if (other is null) - throw new ArgumentNullException(nameof(other)); - - SyncValue = other; - } - - /// - public override string Id => _wrapped?.Id; - - /// - public override Response Value => SyncValue; - - /// - public override bool HasCompleted => !IsLongRunningOperation || _wrapped.HasCompleted; - - /// - public override bool HasValue => !IsLongRunningOperation || _wrapped.HasValue; - - /// - public override Response GetRawResponse() - { - return CompletedSynchronously ? SyncValue : _wrapped.GetRawResponse(); - } - - /// - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - return CompletedSynchronously ? SyncValue : _wrapped.UpdateStatus(cancellationToken); - } - - /// - public override async ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - return CompletedSynchronously ? SyncValue : await _wrapped.UpdateStatusAsync(cancellationToken).ConfigureAwait(false); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - CancellationToken cancellationToken = default) - { - return CompletedSynchronously - ? new WrappingResponse(SyncValue) - : await _wrapped.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - TimeSpan pollingInterval, - CancellationToken cancellationToken) - { - return CompletedSynchronously - ? new WrappingResponse(SyncValue) - : await _wrapped.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false); - } - - /// - /// A class which wraps a response with no body. - /// - internal class WrappingResponse : ArmResponse + /// The response which has no body. + internal VoidArmOperation(Response response) + : base(response) { - private readonly Response _wrapped; - - /// - /// Initializes a new instance of the class. - /// - /// The response object to wrap. - public WrappingResponse(Response wrapped) - { - _wrapped = wrapped; - } - - /// - public override Response Value => _wrapped; - - /// - public override Response GetRawResponse() - { - return _wrapped; - } } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs index 5a88837c374b..f516a406a80f 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupContainer.cs @@ -133,8 +133,8 @@ public override ArmOperation StartCreateOrUpdate(string name, Res try { return new PhArmOperation( - Operations.CreateOrUpdate(name, resourceDetails, cancellationToken), - g => new ResourceGroup(Parent, new ResourceGroupData(g))); + Operations.CreateOrUpdate(name, resourceDetails, cancellationToken), + g => new ResourceGroup(Parent, new ResourceGroupData(g))); } catch (Exception e) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs index b3a6a5da78d2..2b2f803bea88 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/ResourceGroupOperations.cs @@ -116,14 +116,14 @@ public virtual async Task DeleteAsync(CancellationToken cancellatio /// /// Details on long running operation object. /// - public virtual ArmOperation StartDelete(CancellationToken cancellationToken = default) + public virtual ArmOperation StartDelete(CancellationToken cancellationToken = default) { using var scope = Diagnostics.CreateScope("ResourceGroupOperations.StartDelete"); scope.Start(); try { - return new VoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.Name, cancellationToken)); } catch (Exception e) { @@ -140,14 +140,14 @@ public virtual ArmOperation StartDelete(CancellationToken cancellation /// /// Details on long running operation object. /// - public virtual async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public virtual async Task StartDeleteAsync(CancellationToken cancellationToken = default) { using var scope = Diagnostics.CreateScope("ResourceGroupOperations.StartDelete"); scope.Start(); try { - return new VoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.Name, cancellationToken).ConfigureAwait(false)); } catch (Exception e) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs deleted file mode 100644 index d430f210e2c1..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Resources/ResourceGroupData.Serialization.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System.Collections.Generic; -using System.Text.Json; -using Azure.Core; -using Azure.ResourceManager.Resources.Models; - -namespace Azure.ResourceManager.Core -{ - public partial class ResourceGroupData : TrackedResource, IUtf8JsonSerializable - { - void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) - { - writer.WriteStartObject(); - if (Optional.IsDefined(Properties)) - { - writer.WritePropertyName("properties"); - writer.WriteObjectValue(Properties); - } - writer.WritePropertyName("location"); - writer.WriteStringValue(Location); - if (Optional.IsDefined(ManagedBy)) - { - writer.WritePropertyName("managedBy"); - writer.WriteStringValue(ManagedBy); - } - if (Optional.IsCollectionDefined(Tags)) - { - writer.WritePropertyName("tags"); - writer.WriteStartObject(); - foreach (var item in Tags) - { - writer.WritePropertyName(item.Key); - writer.WriteStringValue(item.Value); - } - writer.WriteEndObject(); - } - writer.WriteEndObject(); - } - - internal static ResourceGroup DeserializeResourceGroup(JsonElement element) - { - Optional id = default; - Optional name = default; - Optional type = default; - Optional properties = default; - string location = default; - Optional managedBy = default; - Optional> tags = default; - foreach (var property in element.EnumerateObject()) - { - if (property.NameEquals("id")) - { - id = property.Value.GetString(); - continue; - } - if (property.NameEquals("name")) - { - name = property.Value.GetString(); - continue; - } - if (property.NameEquals("type")) - { - type = property.Value.GetString(); - continue; - } - if (property.NameEquals("properties")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } - properties = ResourceGroupProperties.DeserializeResourceGroupProperties(property.Value); - continue; - } - if (property.NameEquals("location")) - { - location = property.Value.GetString(); - continue; - } - if (property.NameEquals("managedBy")) - { - managedBy = property.Value.GetString(); - continue; - } - if (property.NameEquals("tags")) - { - if (property.Value.ValueKind == JsonValueKind.Null) - { - property.ThrowNonNullablePropertyIsNull(); - continue; - } - Dictionary dictionary = new Dictionary(); - foreach (var property0 in property.Value.EnumerateObject()) - { - dictionary.Add(property0.Name, property0.Value.GetString()); - } - tags = dictionary; - continue; - } - } - return new ResourceGroupData(new Azure.ResourceManager.Resources.Models.ResourceGroup(id.Value, name.Value, type.Value, properties.Value, location, managedBy.Value, Optional.ToDictionary(tags))); - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs deleted file mode 100644 index be85a7c39829..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/UpdateResourceGroupOperation.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Azure.Core; -using Azure.Core.Pipeline; - -namespace Azure.ResourceManager.Core -{ - internal class UpdateResourceGroupOperation : ValueArmOperation, IOperationSource - { - private readonly ArmOperationHelpers _operation; - - public UpdateResourceGroupOperation() - { - } - - ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) - { - using var document = JsonDocument.Parse(response.ContentStream); - return ResourceGroup.DeserializeGalleryImage(document.RootElement); - } - - async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) - { - using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); - return ResourceGroup.DeserializeGalleryImage(document.RootElement); - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs index a042dd2bc58b..f9a349a1ecd0 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs @@ -13,7 +13,6 @@ public class ResourceTypeFilterTests [TestCase] public void TestResourceTypeFilterParamCheck() { - Assert.Throws(() => { new VoidArmOperation((Operation)null); }); Assert.Throws(() => { new VoidArmOperation((Response)null); }); } } From 2f90c91ac6a7b99f4db70a49d2a615573be68bba Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 13 Apr 2021 22:29:16 -0700 Subject: [PATCH 05/15] finalize changes before testing --- .../UpdateResourceGroupOperation.cs | 34 ++++++---- .../src/Operation/ArmOperation.cs | 32 +++++++--- .../src/Operation/PhArmOperation.cs | 20 +++++- .../src/Operation/PhNoValueArmOperation.cs | 35 ++++++++++ .../src/Operation/PhValueArmOperation.cs | 43 +++++++++++++ .../src/Operation/PhVoidArmOperation.cs | 35 ++++++---- .../src/Operation/ValueArmOperation.cs | 13 ---- .../src/Operation/VoidArmOperation.cs | 20 ------ .../tests/Unit/ResourceTypeFilterTests.cs | 2 +- .../authorization/RoleAssignmentOperations.cs | 16 ++--- .../compute/AvailabilitySetOperations.cs | 16 ++--- .../compute/VirtualMachineOperations.cs | 64 +++++++++---------- .../network/NetworkInterfaceOperations.cs | 16 ++--- .../network/NetworkSecurityGroupOperations.cs | 16 ++--- .../network/PublicIpAddressOperations.cs | 16 ++--- .../Proto.Client/network/SubnetOperations.cs | 16 ++--- .../network/VirtualNetworkOperations.cs | 16 ++--- .../Proto.Client/src/Program.cs | 2 +- 18 files changed, 255 insertions(+), 157 deletions(-) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs index 12b58c4a8966..2cbfc34a9e13 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs @@ -8,7 +8,7 @@ namespace Azure.ResourceManager.Core { - internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource + internal class UpdateResourceGroupOperation : ArmOperation { private readonly ResourceOperationsBase _operations; @@ -16,36 +16,46 @@ protected UpdateResourceGroupOperation() { } + internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Response response) + : base(response) + { + _operations = operations; + } + /// /// Initializes a new instance of the class. /// - /// The operation source to use. /// The arm operations object to copy from. /// The original request. - /// The original response. - internal UpdateResourceGroupOperation(IOperationSource source, ResourceOperationsBase operations, Request request, Response response) - : base(source, operations.Diagnostics, ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), request, response, "UpdateResourceGroupOperation") + /// The original response. + internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Request request, Response response) + : base(operations.Diagnostics, + ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), + request, + response, + OperationFinalStateVia.Location, + "UpdateResourceGroupOperation") { _operations = operations; } - ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) + public override ResourceGroup CreateResult(Response response, CancellationToken cancellationToken) { using var document = JsonDocument.Parse(response.ContentStream); return GetResourceGrouop(document); } + public override async ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + return GetResourceGrouop(document); + } + private ResourceGroup GetResourceGrouop(JsonDocument document) { var method = typeof(ResourceManager.Resources.Models.ResourceGroup).GetMethod("DeserializeResourceGroup", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); var obj = method.Invoke(null, new object[] { document.RootElement }); return new ResourceGroup(_operations, new ResourceGroupData(obj as ResourceManager.Resources.Models.ResourceGroup)); } - - async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) - { - using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); - return GetResourceGrouop(document); - } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index 91029ec2b479..b4ec171be1fa 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -12,7 +12,7 @@ namespace Azure.ResourceManager.Core /// /// Abstract class for long-running or synchronous applications. /// - public abstract class ArmOperation : Operation + public abstract class ArmOperation : Operation, IOperationSource { private readonly ArmOperationHelpers _operation; private readonly Response _voidResponse; @@ -27,15 +27,15 @@ protected ArmOperation() /// /// Initializes a new instance of the class. /// - /// The operation source to use. /// The client diagnostics to use. /// The HttpPipeline to use. /// The original request. /// The original response. + /// Where the final state comes from. /// The scope name to use. - internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName) + internal ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) { - _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName); + _operation = new ArmOperationHelpers(this, clientDiagnostics, pipeline, request, response, finalStateVia, scopeName); } /// @@ -134,6 +134,14 @@ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } + +#pragma warning disable CA2119 // Seal methods that satisfy private interfaces + /// + public abstract Response CreateResult(Response response, CancellationToken cancellationToken); + + /// + public abstract ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken); +#pragma warning restore CA2119 // Seal methods that satisfy private interfaces } /// @@ -141,7 +149,7 @@ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken /// /// The to return representing the result of the ArmOperation. #pragma warning disable SA1402 // File may only contain a single type - public abstract class ArmOperation : Operation + public abstract class ArmOperation : Operation, IOperationSource where TOperations : notnull #pragma warning restore SA1402 // File may only contain a single type { @@ -170,15 +178,15 @@ protected ArmOperation(Response response) /// /// Initializes a new instance of the class. /// - /// The operation source to use. /// The client diagnostics to use. /// The HttpPipeline to use. /// The original request. /// The original response. + /// Where the final state comes from. /// The scope name to use. - internal ArmOperation(IOperationSource source, ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, string scopeName) + internal ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) { - _operation = new ArmOperationHelpers(source, clientDiagnostics, pipeline, request, response, OperationFinalStateVia.Location, scopeName); + _operation = new ArmOperationHelpers(this, clientDiagnostics, pipeline, request, response, finalStateVia, scopeName); } private bool _doesWrapOperation => _valueResponse is null; @@ -267,5 +275,13 @@ public virtual Response WaitForCompletion(int pollingInterval, Canc Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } + +#pragma warning disable CA2119 // Seal methods that satisfy private interfaces + /// + public abstract TOperations CreateResult(Response response, CancellationToken cancellationToken); + + /// + public abstract ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken); +#pragma warning restore CA2119 // Seal methods that satisfy private interfaces } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index df48e26e9ecd..e38079713ef1 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. using System; +using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -46,7 +48,7 @@ public PhArmOperation(Operation wrapped, Func conve /// The function used to convert from existing type to new type. public PhArmOperation(Response wrapped, Func converter) { - _wrappedResponseOperation = new ValueArmOperation(wrapped); + _wrappedResponseOperation = new PhValueArmOperation(wrapped); _converter = converter; } @@ -121,5 +123,21 @@ public override Response WaitForCompletion(int pollingInterval, Can Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } + + /// + public override TOperations CreateResult(Response response, CancellationToken cancellationToken) + { + using var document = JsonDocument.Parse(response.ContentStream); + var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + } + + /// + public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs new file mode 100644 index 000000000000..e6a62fd54d1f --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Threading; +using System.Threading.Tasks; + +namespace Azure.ResourceManager.Core +{ + /// + /// A calss representing an arm operation wrapper object. + /// + internal class PhNoValueArmOperation : ArmOperation + { + /// + /// + /// + /// + public PhNoValueArmOperation(Response wrapped) + :base(wrapped) + { + } + + /// + public override Response CreateResult(Response response, CancellationToken cancellationToken) + { + return response; + } + + /// + public override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + return new ValueTask(response); + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs new file mode 100644 index 000000000000..5610d7a07e05 --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace Azure.ResourceManager.Core +{ + /// + /// A calss representing an arm operation wrapper object. + /// + internal class PhValueArmOperation : ArmOperation + where TOperations : class + { + /// + /// + /// + /// + public PhValueArmOperation(Response wrapped) + :base(wrapped) + { + } + + /// + public override TOperations CreateResult(Response response, CancellationToken cancellationToken) + { + using var document = JsonDocument.Parse(response.ContentStream); + var method = typeof(TOperations).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + } + + /// + public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + var method = typeof(TOperations).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + } + } +} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs index 2c94407f519b..d692ceb4ec09 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs @@ -38,7 +38,7 @@ public PhVoidArmOperation(Operation wrapped) /// The results to wrap. public PhVoidArmOperation(Response wrapped) { - _wrappedResponseOperation = new VoidArmOperation(wrapped); + _wrappedResponseOperation = new PhNoValueArmOperation(wrapped); } private bool _doesWrapOperation => _wrappedResponseOperation is null; @@ -46,15 +46,9 @@ public PhVoidArmOperation(Response wrapped) /// public override string Id => _wrappedOperation?.Id; - /// - public override Response Value => throw new InvalidOperationException(); - /// public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted; - /// - public override bool HasValue => false; - /// public override Response GetRawResponse() { @@ -78,21 +72,24 @@ public override ValueTask UpdateStatusAsync(CancellationToken cancella /// public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) { - return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); + var task = WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken); + return await task.ConfigureAwait(false); } /// public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) { - return _doesWrapOperation - ? Response.FromValue(await _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse()) - : Response.FromValue(await _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false), _wrappedOperation.GetRawResponse()); + var task = _doesWrapOperation + ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken) + : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken); + var value = await task.ConfigureAwait(false); + return value; } /// public override Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); } /// @@ -103,11 +100,23 @@ public override Response WaitForCompletion(int pollingInterval, CancellationToke UpdateStatus(cancellationToken); if (HasCompleted) { - return Response.FromValue(Value, GetRawResponse()); + return Value; } Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } + + /// + public override Response CreateResult(Response response, CancellationToken cancellationToken) + { + return response; + } + + /// + public override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + return new ValueTask(response); + } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs deleted file mode 100644 index e546235de64d..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ValueArmOperation.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Azure.ResourceManager.Core -{ - internal class ValueArmOperation : ArmOperation - { - internal ValueArmOperation(Response operation) - : base(operation) - { - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs deleted file mode 100644 index 07f2d6679f3f..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/VoidArmOperation.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Azure.ResourceManager.Core -{ - /// - /// Generic ARM long running operation class for operations with no returned value - /// - internal sealed class VoidArmOperation : ArmOperation - { - /// - /// Initializes a new instance of the class. - /// - /// The response which has no body. - internal VoidArmOperation(Response response) - : base(response) - { - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs index f9a349a1ecd0..ffe30846fa3b 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs @@ -13,7 +13,7 @@ public class ResourceTypeFilterTests [TestCase] public void TestResourceTypeFilterParamCheck() { - Assert.Throws(() => { new VoidArmOperation((Response)null); }); + Assert.Throws(() => { new PhVoidArmOperation((Response)null); }); } } } diff --git a/sdk/resourcemanager/Proto.Client/authorization/RoleAssignmentOperations.cs b/sdk/resourcemanager/Proto.Client/authorization/RoleAssignmentOperations.cs index adc08ef924d5..445c5b9a24d0 100644 --- a/sdk/resourcemanager/Proto.Client/authorization/RoleAssignmentOperations.cs +++ b/sdk/resourcemanager/Proto.Client/authorization/RoleAssignmentOperations.cs @@ -62,27 +62,27 @@ internal RoleAssignmentOperations(OperationsBase operation, ResourceIdentifier i private RoleAssignmentsOperations Operations { get; } /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.DeleteById(Id, cancellationToken).GetRawResponse()); + return ArmResponse.FromResponse(Operations.DeleteById(Id, cancellationToken).GetRawResponse()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.DeleteByIdAsync(Id, cancellationToken)).GetRawResponse()); + return ArmResponse.FromResponse((await Operations.DeleteByIdAsync(Id, cancellationToken)).GetRawResponse()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.DeleteById(Id, cancellationToken).GetRawResponse()); + return new PhVoidArmOperation(Operations.DeleteById(Id, cancellationToken).GetRawResponse()); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation((await Operations.DeleteByIdAsync(Id, cancellationToken)).GetRawResponse()); + return new PhVoidArmOperation((await Operations.DeleteByIdAsync(Id, cancellationToken)).GetRawResponse()); } /// diff --git a/sdk/resourcemanager/Proto.Client/compute/AvailabilitySetOperations.cs b/sdk/resourcemanager/Proto.Client/compute/AvailabilitySetOperations.cs index b35e3ae633bd..2abd922c1d86 100644 --- a/sdk/resourcemanager/Proto.Client/compute/AvailabilitySetOperations.cs +++ b/sdk/resourcemanager/Proto.Client/compute/AvailabilitySetOperations.cs @@ -58,27 +58,27 @@ protected AvailabilitySetOperations(ResourceOperationsBase options, ResourceGrou ClientOptions.Convert()).AvailabilitySets; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.Delete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return ArmResponse.FromResponse(Operations.Delete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse(await Operations.DeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return ArmResponse.FromResponse(await Operations.DeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.Delete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.Delete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.DeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.DeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineOperations.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineOperations.cs index 5b5a04c8f6c8..9c6ffc18884c 100644 --- a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineOperations.cs +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineOperations.cs @@ -70,27 +70,27 @@ public static VirtualMachineOperations FromGeneric(GenericResourceOperations gen } /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } #region PowerOn @@ -98,42 +98,42 @@ public async Task> StartDeleteAsync(CancellationToken can /// The operation to start a virtual machine. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - public ArmResponse PowerOn(CancellationToken cancellationToken = default) + /// A response with the operation for this resource. + public ArmResponse PowerOn(CancellationToken cancellationToken = default) { var operation = Operations.StartStart(Id.ResourceGroupName, Id.Name, cancellationToken); - return new ArmResponse(operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse(operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// /// The operation to start a virtual machine. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A that on completion returns a response with the operation for this resource. - public async Task> PowerOnAsync(CancellationToken cancellationToken = default) + /// A that on completion returns a response with the operation for this resource. + public async Task PowerOnAsync(CancellationToken cancellationToken = default) { var operation = await Operations.StartStartAsync(Id.ResourceGroupName, Id.Name, cancellationToken).ConfigureAwait(false); - return new ArmResponse(await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); + return ArmResponse.FromResponse(await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); } /// /// The operation to start a virtual machine. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// An that allows polling for completion of the operation. - public ArmOperation StartPowerOn(CancellationToken cancellationToken = default) + /// An that allows polling for completion of the operation. + public ArmOperation StartPowerOn(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartStart(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartStart(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// /// The operation to start a virtual machine. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A that on completion returns an that allows polling for completion of the operation. - public async Task> StartPowerOnAsync(CancellationToken cancellationToken = default) + /// A that on completion returns an that allows polling for completion of the operation. + public async Task StartPowerOnAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartStartAsync(Id.ResourceGroupName, Id.Name, cancellationToken).ConfigureAwait(false)); + return new PhVoidArmOperation(await Operations.StartStartAsync(Id.ResourceGroupName, Id.Name, cancellationToken).ConfigureAwait(false)); } #endregion @@ -143,11 +143,11 @@ public async Task> StartPowerOnAsync(CancellationToken ca /// /// The parameter to request non-graceful VM shutdown. True value for this flag indicates non-graceful shutdown whereas false indicates otherwise. Default value for this flag is false if not specified. /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - public ArmResponse PowerOff(bool? skipShutdown = null, CancellationToken cancellationToken = default) + /// A response with the operation for this resource. + public ArmResponse PowerOff(bool? skipShutdown = null, CancellationToken cancellationToken = default) { var operation = Operations.StartPowerOff(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken); - return new ArmResponse(operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse(operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// @@ -155,11 +155,11 @@ public ArmResponse PowerOff(bool? skipShutdown = null, CancellationTok /// /// The parameter to request non-graceful VM shutdown. True value for this flag indicates non-graceful shutdown whereas false indicates otherwise. Default value for this flag is false if not specified. /// A token to allow the caller to cancel the call to the service. The default value is . - /// A that on completion returns a response with the operation for this resource. - public async Task> PowerOffAsync(bool? skipShutdown = null, CancellationToken cancellationToken = default) + /// A that on completion returns a response with the operation for this resource. + public async Task PowerOffAsync(bool? skipShutdown = null, CancellationToken cancellationToken = default) { var operation = await Operations.StartPowerOffAsync(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken).ConfigureAwait(false); - return new ArmResponse(await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); + return ArmResponse.FromResponse(await operation.WaitForCompletionAsync(cancellationToken).ConfigureAwait(false)); } /// @@ -167,10 +167,10 @@ public async Task> PowerOffAsync(bool? skipShutdown = null /// /// The parameter to request non-graceful VM shutdown. True value for this flag indicates non-graceful shutdown whereas false indicates otherwise. Default value for this flag is false if not specified. /// A token to allow the caller to cancel the call to the service. The default value is . - /// An that allows polling for completion of the operation. - public ArmOperation StartPowerOff(bool? skipShutdown = null, CancellationToken cancellationToken = default) + /// An that allows polling for completion of the operation. + public ArmOperation StartPowerOff(bool? skipShutdown = null, CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartPowerOff(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken)); + return new PhVoidArmOperation(Operations.StartPowerOff(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken)); } /// @@ -178,10 +178,10 @@ public ArmOperation StartPowerOff(bool? skipShutdown = null, Cancellat /// /// The parameter to request non-graceful VM shutdown. True value for this flag indicates non-graceful shutdown whereas false indicates otherwise. Default value for this flag is false if not specified. /// A token to allow the caller to cancel the call to the service. The default value is . - /// A that on completion returns an that allows polling for completion of the operation. - public async Task> StartPowerOffAsync(bool? skipShutdown = null, CancellationToken cancellationToken = default) + /// A that on completion returns an that allows polling for completion of the operation. + public async Task StartPowerOffAsync(bool? skipShutdown = null, CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartPowerOffAsync(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken).ConfigureAwait(false)); + return new PhVoidArmOperation(await Operations.StartPowerOffAsync(Id.ResourceGroupName, Id.Name, skipShutdown, cancellationToken).ConfigureAwait(false)); } #endregion diff --git a/sdk/resourcemanager/Proto.Client/network/NetworkInterfaceOperations.cs b/sdk/resourcemanager/Proto.Client/network/NetworkInterfaceOperations.cs index 60ffdb798789..6e022831b687 100644 --- a/sdk/resourcemanager/Proto.Client/network/NetworkInterfaceOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/NetworkInterfaceOperations.cs @@ -49,29 +49,29 @@ protected NetworkInterfaceOperations(ResourceOperationsBase options, ResourceGro ClientOptions.Convert()).NetworkInterfaces; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/network/NetworkSecurityGroupOperations.cs b/sdk/resourcemanager/Proto.Client/network/NetworkSecurityGroupOperations.cs index f9a72e436880..e9d0a478fd22 100644 --- a/sdk/resourcemanager/Proto.Client/network/NetworkSecurityGroupOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/NetworkSecurityGroupOperations.cs @@ -166,29 +166,29 @@ await Operations.UpdateTagsAsync(Id.ResourceGroupName, Id.Name, patchable, cance } /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/network/PublicIpAddressOperations.cs b/sdk/resourcemanager/Proto.Client/network/PublicIpAddressOperations.cs index 0e8c4d87f2d8..4b6a342409df 100644 --- a/sdk/resourcemanager/Proto.Client/network/PublicIpAddressOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/PublicIpAddressOperations.cs @@ -61,29 +61,29 @@ protected PublicIpAddressOperations(ResourceOperationsBase options, ResourceIden ClientOptions.Convert()).PublicIPAddresses; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/network/SubnetOperations.cs b/sdk/resourcemanager/Proto.Client/network/SubnetOperations.cs index 5ab4f9bd5372..8e7a2478e9b9 100644 --- a/sdk/resourcemanager/Proto.Client/network/SubnetOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/SubnetOperations.cs @@ -48,30 +48,30 @@ protected SubnetOperations(ResourceOperationsBase options, ResourceIdentifier id ClientOptions.Convert()).Subnets; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken) + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)) + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/network/VirtualNetworkOperations.cs b/sdk/resourcemanager/Proto.Client/network/VirtualNetworkOperations.cs index 6a7db8239d72..a8d82492b9ca 100644 --- a/sdk/resourcemanager/Proto.Client/network/VirtualNetworkOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/VirtualNetworkOperations.cs @@ -60,27 +60,27 @@ protected VirtualNetworkOperations(ResourceOperationsBase options, ResourceIdent ClientOptions.Convert()).VirtualNetworks; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/src/Program.cs b/sdk/resourcemanager/Proto.Client/src/Program.cs index 3af054d1672c..d032f6c8de6c 100644 --- a/sdk/resourcemanager/Proto.Client/src/Program.cs +++ b/sdk/resourcemanager/Proto.Client/src/Program.cs @@ -11,7 +11,7 @@ static void Main(string[] args) Scenario scenario = null; try { - scenario = ScenarioFactory.GetScenario(Scenarios.GetFromOperations); + scenario = ScenarioFactory.GetScenario(Scenarios.StartCreateSingleVmExampleAsync); scenario.Execute(); } finally From d0407f631ed2c6403ded999f1fa9eb235a8e511b Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 13 Apr 2021 22:35:48 -0700 Subject: [PATCH 06/15] update ph overloads --- .../src/Operation/PhArmOperation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index e38079713ef1..ddbcd9445829 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -129,7 +129,7 @@ public override TOperations CreateResult(Response response, CancellationToken ca { using var document = JsonDocument.Parse(response.ContentStream); var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + return _converter(method.Invoke(null, new object[] { document.RootElement }) as TModel); } /// @@ -137,7 +137,7 @@ public async override ValueTask CreateResultAsync(Response response { using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + return _converter(method.Invoke(null, new object[] { document.RootElement }) as TModel); } } } From c7305e8a1afb340319b921890a8f6d8fe0bda858 Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 13 Apr 2021 22:45:26 -0700 Subject: [PATCH 07/15] move pipeline creation into armoperation --- .../tests/TestClients/ArmOperationTest.cs | 16 ++++++++++++++++ .../UpdateResourceGroupOperation.cs | 3 +-- .../src/Operation/ArmOperation.cs | 16 ++++++++-------- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs index 95ef4c777407..81fd71b9fcb3 100644 --- a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs @@ -2,6 +2,8 @@ // Licensed under the MIT License. using System; +using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Azure.ResourceManager.Core; @@ -53,5 +55,19 @@ public override Response UpdateStatus(CancellationToken cancellationToken = defa { return Response.FromValue(_value, null) as Response; } + + public override T CreateResult(Response response, CancellationToken cancellationToken) + { + using var document = JsonDocument.Parse(response.ContentStream); + var method = typeof(T).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as T; + } + + public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); + var method = typeof(T).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); + return method.Invoke(null, new object[] { document.RootElement }) as T; + } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs index 2cbfc34a9e13..70584b1c082f 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs @@ -29,8 +29,7 @@ internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Respons /// The original request. /// The original response. internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Request request, Response response) - : base(operations.Diagnostics, - ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), + : base(operations, request, response, OperationFinalStateVia.Location, diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index b4ec171be1fa..bbdd1aa5ad9d 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -27,15 +27,15 @@ protected ArmOperation() /// /// Initializes a new instance of the class. /// - /// The client diagnostics to use. - /// The HttpPipeline to use. + /// The operations to copy connection info from. /// The original request. /// The original response. /// Where the final state comes from. /// The scope name to use. - internal ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) + internal ArmOperation(ResourceOperationsBase operations, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) { - _operation = new ArmOperationHelpers(this, clientDiagnostics, pipeline, request, response, finalStateVia, scopeName); + var pipeline = ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions); + _operation = new ArmOperationHelpers(this, operations.Diagnostics, pipeline, request, response, finalStateVia, scopeName); } /// @@ -178,15 +178,15 @@ protected ArmOperation(Response response) /// /// Initializes a new instance of the class. /// - /// The client diagnostics to use. - /// The HttpPipeline to use. + /// The operations to copy connection info from. /// The original request. /// The original response. /// Where the final state comes from. /// The scope name to use. - internal ArmOperation(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) + internal ArmOperation(ResourceOperationsBase operations, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) { - _operation = new ArmOperationHelpers(this, clientDiagnostics, pipeline, request, response, finalStateVia, scopeName); + var pipeline = ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions); + _operation = new ArmOperationHelpers(this, operations.Diagnostics, pipeline, request, response, finalStateVia, scopeName); } private bool _doesWrapOperation => _valueResponse is null; From 30e529db4de5d1d30272b3eb8aac7f5d2f0c7c31 Mon Sep 17 00:00:00 2001 From: m-nash Date: Wed, 21 Apr 2021 10:22:50 -0700 Subject: [PATCH 08/15] wip --- .../Azure.Core/tests/Azure.Core.Tests.csproj | 1 + .../tests/TestClients/ArmOperationTest.cs | 52 +++---- .../UpdateResourceGroupOperation.cs | 47 +++++-- .../src/Operation/ArmOperation.cs | 90 +----------- .../src/Operation/TempArmOperationHelper.cs | 130 ++++++++++++++++++ 5 files changed, 188 insertions(+), 132 deletions(-) create mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs diff --git a/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj b/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj index ef9975b67d5e..c751dd595e36 100644 --- a/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj +++ b/sdk/core/Azure.Core/tests/Azure.Core.Tests.csproj @@ -4,6 +4,7 @@ $(RequiredTargetFrameworks) $(DefineConstants);HAS_INTERNALS_VISIBLE_CORE true + true diff --git a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs index 81fd71b9fcb3..7a1a5acec1c7 100644 --- a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs @@ -6,6 +6,7 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Azure.Core; using Azure.ResourceManager.Core; namespace Azure.Core.Tests @@ -13,47 +14,32 @@ namespace Azure.Core.Tests public class ArmOperationTest : ArmOperation where T : class { - private T _value; - protected ArmOperationTest() - { - } - - public ArmOperationTest(T value) - { - _value = value; - } - - public override string Id => "testId"; - - public override T Value => _value; - - public override bool HasCompleted => true; + private readonly ResourceOperationsBase _operations; - public override bool HasValue => true; - - public override Response GetRawResponse() - { - return Response.FromValue(_value, null) as Response; - } - - public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - return new ValueTask>(Response.FromValue(_value, null)); - } - - public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + protected ArmOperationTest() { - return new ValueTask>(Response.FromValue(_value, null)); } - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + internal ArmOperationTest(ResourceOperationsBase operations, Response response) + : base(response) { - return new ValueTask(Response.FromValue(_value, null) as Response); + _operations = operations; } - public override Response UpdateStatus(CancellationToken cancellationToken = default) + /// + /// Initializes a new instance of the class. + /// + /// The arm operations object to copy from. + /// The original request. + /// The original response. + internal ArmOperationTest(ResourceOperationsBase operations, Request request, Response response) + : base(operations, + request, + response, + OperationFinalStateVia.Location, + "UpdateResourceGroupOperation") { - return Response.FromValue(_value, null) as Response; + _operations = operations; } public override T CreateResult(Response response, CancellationToken cancellationToken) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs index 70584b1c082f..23be816b7725 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs @@ -5,20 +5,26 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core; +using Azure.Core.Pipeline; namespace Azure.ResourceManager.Core { - internal class UpdateResourceGroupOperation : ArmOperation + internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource { private readonly ResourceOperationsBase _operations; + private readonly TempArmOperationHelper _operationHelper; protected UpdateResourceGroupOperation() { } - internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Response response) - : base(response) + internal UpdateResourceGroupOperation(ResourceOperationsBase operations, ArmResponse response) { + _operationHelper = new TempArmOperationHelper( + response, + operations, + OperationFinalStateVia.Location, + "UpdateResourceGroupOperation"); _operations = operations; } @@ -29,22 +35,43 @@ internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Respons /// The original request. /// The original response. internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Request request, Response response) - : base(operations, - request, - response, - OperationFinalStateVia.Location, - "UpdateResourceGroupOperation") { + _operationHelper = new TempArmOperationHelper( + this, + new ClientDiagnostics(operations.ClientOptions), + ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), + request, + response, + OperationFinalStateVia.Location, + "UpdateResourceGroupOperation"); _operations = operations; } - public override ResourceGroup CreateResult(Response response, CancellationToken cancellationToken) + public override ResourceGroup Value => _operationHelper.Value; + + public override bool HasValue => _operationHelper.HasValue; + + public override string Id => throw new System.NotImplementedException(); + + public override bool HasCompleted => _operationHelper.HasCompleted; + + public override Response GetRawResponse() => _operationHelper.GetRawResponse(); + + public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatus(cancellationToken); + + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatusAsync(cancellationToken); + + public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) => _operationHelper.WaitForCompletionAsync(cancellationToken); + + public override ValueTask> WaitForCompletionAsync(System.TimeSpan pollingInterval, CancellationToken cancellationToken) => _operationHelper.WaitForCompletionAsync(pollingInterval, cancellationToken); + + ResourceGroup IOperationSource.CreateResult(Response response, CancellationToken cancellationToken) { using var document = JsonDocument.Parse(response.ContentStream); return GetResourceGrouop(document); } - public override async ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + async ValueTask IOperationSource.CreateResultAsync(Response response, CancellationToken cancellationToken) { using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); return GetResourceGrouop(document); diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index bbdd1aa5ad9d..62b8bdc1c682 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -149,13 +149,10 @@ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken /// /// The to return representing the result of the ArmOperation. #pragma warning disable SA1402 // File may only contain a single type - public abstract class ArmOperation : Operation, IOperationSource + public abstract class ArmOperation : Operation where TOperations : notnull #pragma warning restore SA1402 // File may only contain a single type { - private readonly ArmOperationHelpers _operation; - private readonly Response _valueResponse; - /// /// Initializes a new instance of the class for mocking. /// @@ -163,83 +160,6 @@ protected ArmOperation() { } - /// - /// Initializes a new instance of the class. - /// - /// The non lro response to wrap. - protected ArmOperation(Response response) - { - if (response is null) - throw new ArgumentNullException(nameof(response)); - - _valueResponse = response; - } - - /// - /// Initializes a new instance of the class. - /// - /// The operations to copy connection info from. - /// The original request. - /// The original response. - /// Where the final state comes from. - /// The scope name to use. - internal ArmOperation(ResourceOperationsBase operations, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) - { - var pipeline = ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions); - _operation = new ArmOperationHelpers(this, operations.Diagnostics, pipeline, request, response, finalStateVia, scopeName); - } - - private bool _doesWrapOperation => _valueResponse is null; - - /// - public override string Id => _operation?.Id; - - /// - public override TOperations Value => _doesWrapOperation ? _operation.Value : _valueResponse.Value; - - /// - public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true; - - /// - public override bool HasValue => _doesWrapOperation ? _operation.HasValue : true; - - /// - public override Response GetRawResponse() - { - return _doesWrapOperation ? _operation.GetRawResponse() : _valueResponse.GetRawResponse(); - } - - /// - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _valueResponse.GetRawResponse(); - } - - /// - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - return _doesWrapOperation - ? _operation.UpdateStatusAsync(cancellationToken) - : new ValueTask(_valueResponse.GetRawResponse()); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - CancellationToken cancellationToken = default) - { - return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - TimeSpan pollingInterval, - CancellationToken cancellationToken) - { - return _doesWrapOperation - ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) - : _valueResponse; - } - /// /// Waits for the completion of the long running operations. /// @@ -275,13 +195,5 @@ public virtual Response WaitForCompletion(int pollingInterval, Canc Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } - -#pragma warning disable CA2119 // Seal methods that satisfy private interfaces - /// - public abstract TOperations CreateResult(Response response, CancellationToken cancellationToken); - - /// - public abstract ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken); -#pragma warning restore CA2119 // Seal methods that satisfy private interfaces } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs new file mode 100644 index 000000000000..aef0bfd6fafd --- /dev/null +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.ResourceManager.Core +{ + internal class TempArmOperationHelper : ArmOperationHelpers + { + private ArmResponse _response; + + public TempArmOperationHelper( + ArmResponse response, + ResourceOperationsBase operationBase, + OperationFinalStateVia finalStateVia, + string scopeName) + : base(null, + new ClientDiagnostics(operationBase.ClientOptions), + ManagementPipelineBuilder.Build(operationBase.Credential, operationBase.BaseUri, operationBase.ClientOptions), + null, + null, + finalStateVia, + scopeName) + { + _response = response; + } + + public TempArmOperationHelper( + IOperationSource source, + ClientDiagnostics clientDiagnostics, + HttpPipeline pipeline, + Request originalRequest, + Response originalResponse, + OperationFinalStateVia finalStateVia, + string scopeName) + :base(source, clientDiagnostics, pipeline, originalRequest, originalResponse, finalStateVia, scopeName) + { + } + + private bool _doesWrapOperation => _response is null; + + /// + public override T Value => _doesWrapOperation ? base.Value : _response.Value; + + /// + public override bool HasCompleted => _doesWrapOperation ? base.HasCompleted : true; + + /// + public override bool HasValue => _doesWrapOperation ? base.HasValue : true; + + /// + public override Response GetRawResponse() + { + return _doesWrapOperation ? base.GetRawResponse() : _response.GetRawResponse(); + } + + /// + public override Response UpdateStatus(CancellationToken cancellationToken = default) + { + return _doesWrapOperation ? base.UpdateStatus(cancellationToken) : _response.GetRawResponse(); + } + + /// + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) + { + return _doesWrapOperation + ? base.UpdateStatusAsync(cancellationToken) + : new ValueTask(_response.GetRawResponse()); + } + + /// + public override async ValueTask> WaitForCompletionAsync( + CancellationToken cancellationToken = default) + { + return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); + } + + /// + public override async ValueTask> WaitForCompletionAsync( + TimeSpan pollingInterval, + CancellationToken cancellationToken) + { + return _doesWrapOperation + ? await base.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) + : _response; + } + + /// + /// Waits for the completion of the long running operations. + /// + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + /// + /// Details on long running operation object. + /// + public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) + { + return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + } + + /// + /// Waits for the completion of the long running operations. + /// + /// The polling interval in seconds to check for status. + /// A token to allow the caller to cancel the call to the service. The default value is . + /// A response with the operation for this resource. + /// + /// Details on long running operation object. + /// + public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + { + while (true) + { + UpdateStatus(cancellationToken); + if (HasCompleted) + { + return Response.FromValue(Value, GetRawResponse()) as ArmResponse; + } + + Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); + } + } + } +} From 7db165a5e002c0236f99b9d3cb9a03c6f108e20b Mon Sep 17 00:00:00 2001 From: m-nash Date: Wed, 28 Apr 2021 15:47:18 -0700 Subject: [PATCH 09/15] updates based on new OperationInternals --- eng/Packages.Data.props | 2 +- .../UpdateResourceGroupOperation.cs | 27 +--- .../src/Operation/ArmOperation.cs | 94 +------------ .../src/Operation/PhArmOperation.cs | 32 ++--- .../src/Operation/PhNoValueArmOperation.cs | 35 ----- .../src/Operation/PhValueArmOperation.cs | 55 +++++--- .../src/Operation/PhVoidArmOperation.cs | 82 ++++------- .../src/Operation/TempArmOperationHelper.cs | 130 ------------------ .../src/Utils/UtilityExtensions.cs | 2 +- .../Scenario/ResourceGroupOperationsTests.cs | 2 +- 10 files changed, 85 insertions(+), 376 deletions(-) rename sdk/resourcemanager/Azure.ResourceManager.Core/src/{LongRunningOperations => Generated}/UpdateResourceGroupOperation.cs (69%) delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs delete mode 100644 sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index 490abb116b5f..78ec3232a02d 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -127,7 +127,7 @@ All should have PrivateAssets="All" set so they don't become pacakge dependencies --> - + diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Generated/UpdateResourceGroupOperation.cs similarity index 69% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Generated/UpdateResourceGroupOperation.cs index 23be816b7725..86b8bea8bbd5 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/LongRunningOperations/UpdateResourceGroupOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Generated/UpdateResourceGroupOperation.cs @@ -12,7 +12,7 @@ namespace Azure.ResourceManager.Core internal class UpdateResourceGroupOperation : ArmOperation, IOperationSource { private readonly ResourceOperationsBase _operations; - private readonly TempArmOperationHelper _operationHelper; + private readonly OperationOrResponseInternals _operationHelper; protected UpdateResourceGroupOperation() { @@ -20,30 +20,7 @@ protected UpdateResourceGroupOperation() internal UpdateResourceGroupOperation(ResourceOperationsBase operations, ArmResponse response) { - _operationHelper = new TempArmOperationHelper( - response, - operations, - OperationFinalStateVia.Location, - "UpdateResourceGroupOperation"); - _operations = operations; - } - - /// - /// Initializes a new instance of the class. - /// - /// The arm operations object to copy from. - /// The original request. - /// The original response. - internal UpdateResourceGroupOperation(ResourceOperationsBase operations, Request request, Response response) - { - _operationHelper = new TempArmOperationHelper( - this, - new ClientDiagnostics(operations.ClientOptions), - ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions), - request, - response, - OperationFinalStateVia.Location, - "UpdateResourceGroupOperation"); + _operationHelper = new OperationOrResponseInternals(response); _operations = operations; } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index 62b8bdc1c682..7a122d69ca40 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -1,22 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Threading; using System.Threading.Tasks; using Azure.Core; -using Azure.Core.Pipeline; namespace Azure.ResourceManager.Core { /// /// Abstract class for long-running or synchronous applications. /// - public abstract class ArmOperation : Operation, IOperationSource + public abstract class ArmOperation : Operation { - private readonly ArmOperationHelpers _operation; - private readonly Response _voidResponse; - /// /// Initializes a new instance of the class for mocking. /// @@ -24,81 +19,6 @@ protected ArmOperation() { } - /// - /// Initializes a new instance of the class. - /// - /// The operations to copy connection info from. - /// The original request. - /// The original response. - /// Where the final state comes from. - /// The scope name to use. - internal ArmOperation(ResourceOperationsBase operations, Request request, Response response, OperationFinalStateVia finalStateVia, string scopeName) - { - var pipeline = ManagementPipelineBuilder.Build(operations.Credential, operations.BaseUri, operations.ClientOptions); - _operation = new ArmOperationHelpers(this, operations.Diagnostics, pipeline, request, response, finalStateVia, scopeName); - } - - /// - /// Initializes a new instance of the class. - /// - /// - protected ArmOperation(Response response) - { - if (response is null) - throw new ArgumentNullException(nameof(response)); - - _voidResponse = response; - } - - /// - private bool _doesWrapOperation => _voidResponse is null; - - /// - public override string Id => _operation?.Id; - - /// - public override Response Value => throw new InvalidOperationException(); - - /// - public override bool HasCompleted => _doesWrapOperation ? _operation.HasCompleted : true; - - /// - public override bool HasValue => false; - - /// - public override Response GetRawResponse() - { - return _doesWrapOperation ? _operation.GetRawResponse() : _voidResponse; - } - - /// - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - return _doesWrapOperation ? _operation.UpdateStatus(cancellationToken) : _voidResponse; - } - - /// - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - return _doesWrapOperation - ? _operation.UpdateStatusAsync(cancellationToken) - : new ValueTask(_voidResponse); - } - - /// - public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); - } - - /// - public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) - { - return _doesWrapOperation - ? await _operation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) - : Response.FromValue(_voidResponse, _voidResponse); - } - /// /// Waits for the completion of the long running operations. /// @@ -109,7 +29,7 @@ public override async ValueTask> WaitForCompletionAsync(TimeS /// public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); } /// @@ -134,14 +54,6 @@ public virtual Response WaitForCompletion(int pollingInterval, CancellationToken Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } - -#pragma warning disable CA2119 // Seal methods that satisfy private interfaces - /// - public abstract Response CreateResult(Response response, CancellationToken cancellationToken); - - /// - public abstract ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken); -#pragma warning restore CA2119 // Seal methods that satisfy private interfaces } /// @@ -170,7 +82,7 @@ protected ArmOperation() /// public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); } /// diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index ddbcd9445829..16a2cf166f8d 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -37,6 +37,12 @@ protected PhArmOperation() /// The function used to convert from existing type to new type. public PhArmOperation(Operation wrapped, Func converter) { + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); + + if (converter is null) + throw new ArgumentNullException(nameof(converter)); + _wrappedOperation = wrapped; _converter = converter; } @@ -48,6 +54,12 @@ public PhArmOperation(Operation wrapped, Func conve /// The function used to convert from existing type to new type. public PhArmOperation(Response wrapped, Func converter) { + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); + + if (converter is null) + throw new ArgumentNullException(nameof(converter)); + _wrappedResponseOperation = new PhValueArmOperation(wrapped); _converter = converter; } @@ -89,7 +101,7 @@ public override ValueTask UpdateStatusAsync(CancellationToken cancella /// public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) { - var task = WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken); + var task = WaitForCompletionAsync(OperationInternals.DefaultPollingInterval, cancellationToken); return await task.ConfigureAwait(false); } @@ -106,7 +118,7 @@ public override async ValueTask> WaitForCompletionAsync(Ti /// public override Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); } /// @@ -123,21 +135,5 @@ public override Response WaitForCompletion(int pollingInterval, Can Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); } } - - /// - public override TOperations CreateResult(Response response, CancellationToken cancellationToken) - { - using var document = JsonDocument.Parse(response.ContentStream); - var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return _converter(method.Invoke(null, new object[] { document.RootElement }) as TModel); - } - - /// - public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) - { - using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); - var method = typeof(TModel).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return _converter(method.Invoke(null, new object[] { document.RootElement }) as TModel); - } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs deleted file mode 100644 index e6a62fd54d1f..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhNoValueArmOperation.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Threading; -using System.Threading.Tasks; - -namespace Azure.ResourceManager.Core -{ - /// - /// A calss representing an arm operation wrapper object. - /// - internal class PhNoValueArmOperation : ArmOperation - { - /// - /// - /// - /// - public PhNoValueArmOperation(Response wrapped) - :base(wrapped) - { - } - - /// - public override Response CreateResult(Response response, CancellationToken cancellationToken) - { - return response; - } - - /// - public override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) - { - return new ValueTask(response); - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs index 5610d7a07e05..0edbf836167e 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs @@ -2,10 +2,9 @@ // Licensed under the MIT License. using System; -using System.Linq; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using Azure.Core; namespace Azure.ResourceManager.Core { @@ -15,29 +14,51 @@ namespace Azure.ResourceManager.Core internal class PhValueArmOperation : ArmOperation where TOperations : class { + private readonly Operation _wrappedOperation; + private readonly OperationOrResponseInternals _wrappedResponseOperation; + + protected PhValueArmOperation() + { + } + + public PhValueArmOperation(Operation wrapped) + { + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); + + _wrappedOperation = wrapped; + } + /// /// /// /// public PhValueArmOperation(Response wrapped) - :base(wrapped) { - } + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); - /// - public override TOperations CreateResult(Response response, CancellationToken cancellationToken) - { - using var document = JsonDocument.Parse(response.ContentStream); - var method = typeof(TOperations).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return method.Invoke(null, new object[] { document.RootElement }) as TOperations; + _wrappedResponseOperation = new OperationOrResponseInternals(wrapped); } - /// - public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) - { - using var document = await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false); - var method = typeof(TOperations).GetMethods().FirstOrDefault(m => m.Name.StartsWith("Deserialize", StringComparison.InvariantCulture) && !m.IsPublic && m.IsStatic); - return method.Invoke(null, new object[] { document.RootElement }) as TOperations; - } + private bool _doesWrapOperation => _wrappedResponseOperation is null; + + public override TOperations Value => _doesWrapOperation ? _wrappedOperation.Value : _wrappedResponseOperation.Value; + + public override bool HasValue => _doesWrapOperation ? _wrappedOperation.HasValue : _wrappedResponseOperation.HasValue; + + public override string Id => _wrappedOperation?.Id; + + public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted; + + public override Response GetRawResponse() => _doesWrapOperation? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse(); + + public override Response UpdateStatus(CancellationToken cancellationToken = default) => _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken); + + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _doesWrapOperation ? _wrappedOperation.UpdateStatusAsync(cancellationToken) : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken); + + public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) => _doesWrapOperation ? _wrappedOperation.WaitForCompletionAsync(cancellationToken) : _wrappedResponseOperation.WaitForCompletionAsync(cancellationToken); + + public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) => _doesWrapOperation ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken) : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken); } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs index d692ceb4ec09..9bed6d9dbda1 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs @@ -13,8 +13,8 @@ namespace Azure.ResourceManager.Core /// public class PhVoidArmOperation : ArmOperation { - private readonly Operation _wrappedOperation; - private readonly ArmOperation _wrappedResponseOperation; + private readonly Operation _wrappedOperation; + private readonly OperationOrResponseInternals _wrappedResponseOperation; /// /// Initializes a new instance of the class for mocking. @@ -27,8 +27,11 @@ protected PhVoidArmOperation() /// Initializes a new instance of the class. /// /// The results to wrap. - public PhVoidArmOperation(Operation wrapped) + public PhVoidArmOperation(Operation wrapped) { + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); + _wrappedOperation = wrapped; } @@ -38,7 +41,10 @@ public PhVoidArmOperation(Operation wrapped) /// The results to wrap. public PhVoidArmOperation(Response wrapped) { - _wrappedResponseOperation = new PhNoValueArmOperation(wrapped); + if (wrapped is null) + throw new ArgumentNullException(nameof(wrapped)); + + _wrappedResponseOperation = new OperationOrResponseInternals(Response.FromValue(wrapped, wrapped)); } private bool _doesWrapOperation => _wrappedResponseOperation is null; @@ -50,73 +56,35 @@ public PhVoidArmOperation(Response wrapped) public override bool HasCompleted => _doesWrapOperation ? _wrappedOperation.HasCompleted : _wrappedResponseOperation.HasCompleted; /// - public override Response GetRawResponse() - { - return _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse(); - } + public override Response GetRawResponse() => _doesWrapOperation ? _wrappedOperation.GetRawResponse() : _wrappedResponseOperation.GetRawResponse(); /// - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - return _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken); - } + public override Response UpdateStatus(CancellationToken cancellationToken = default) => _doesWrapOperation ? _wrappedOperation.UpdateStatus(cancellationToken) : _wrappedResponseOperation.UpdateStatus(cancellationToken); /// - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - return _doesWrapOperation - ? _wrappedOperation.UpdateStatusAsync(cancellationToken) - : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken); - } + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _doesWrapOperation ? _wrappedOperation.UpdateStatusAsync(cancellationToken) : _wrappedResponseOperation.UpdateStatusAsync(cancellationToken); /// - public override async ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + public override async ValueTask WaitForCompletionResponseAsync(CancellationToken cancellationToken = default) { - var task = WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken); + var task = WaitForCompletionResponseAsync(OperationInternals.DefaultPollingInterval, cancellationToken); return await task.ConfigureAwait(false); } /// - public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + public override async ValueTask WaitForCompletionResponseAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) { - var task = _doesWrapOperation - ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken) - : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken); - var value = await task.ConfigureAwait(false); - return value; - } - - /// - public override Response WaitForCompletion(CancellationToken cancellationToken = default) - { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); - } - - /// - public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) - { - while (true) + if (_doesWrapOperation) { - UpdateStatus(cancellationToken); - if (HasCompleted) - { - return Value; - } - - Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); + return await _wrappedOperation.WaitForCompletionResponseAsync(pollingInterval, cancellationToken).ConfigureAwait(false); + } + else + { + var taskResponseResponse = await _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false); + var taskResponse = Task.FromResult(taskResponseResponse.Value); + var valueTask = new ValueTask(taskResponse); + return await valueTask.ConfigureAwait(false); } - } - - /// - public override Response CreateResult(Response response, CancellationToken cancellationToken) - { - return response; - } - - /// - public override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) - { - return new ValueTask(response); } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs deleted file mode 100644 index aef0bfd6fafd..000000000000 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/TempArmOperationHelper.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Azure.Core; -using Azure.Core.Pipeline; - -namespace Azure.ResourceManager.Core -{ - internal class TempArmOperationHelper : ArmOperationHelpers - { - private ArmResponse _response; - - public TempArmOperationHelper( - ArmResponse response, - ResourceOperationsBase operationBase, - OperationFinalStateVia finalStateVia, - string scopeName) - : base(null, - new ClientDiagnostics(operationBase.ClientOptions), - ManagementPipelineBuilder.Build(operationBase.Credential, operationBase.BaseUri, operationBase.ClientOptions), - null, - null, - finalStateVia, - scopeName) - { - _response = response; - } - - public TempArmOperationHelper( - IOperationSource source, - ClientDiagnostics clientDiagnostics, - HttpPipeline pipeline, - Request originalRequest, - Response originalResponse, - OperationFinalStateVia finalStateVia, - string scopeName) - :base(source, clientDiagnostics, pipeline, originalRequest, originalResponse, finalStateVia, scopeName) - { - } - - private bool _doesWrapOperation => _response is null; - - /// - public override T Value => _doesWrapOperation ? base.Value : _response.Value; - - /// - public override bool HasCompleted => _doesWrapOperation ? base.HasCompleted : true; - - /// - public override bool HasValue => _doesWrapOperation ? base.HasValue : true; - - /// - public override Response GetRawResponse() - { - return _doesWrapOperation ? base.GetRawResponse() : _response.GetRawResponse(); - } - - /// - public override Response UpdateStatus(CancellationToken cancellationToken = default) - { - return _doesWrapOperation ? base.UpdateStatus(cancellationToken) : _response.GetRawResponse(); - } - - /// - public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) - { - return _doesWrapOperation - ? base.UpdateStatusAsync(cancellationToken) - : new ValueTask(_response.GetRawResponse()); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - CancellationToken cancellationToken = default) - { - return await WaitForCompletionAsync(ArmOperationHelpers.DefaultPollingInterval, cancellationToken).ConfigureAwait(false); - } - - /// - public override async ValueTask> WaitForCompletionAsync( - TimeSpan pollingInterval, - CancellationToken cancellationToken) - { - return _doesWrapOperation - ? await base.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) - : _response; - } - - /// - /// Waits for the completion of the long running operations. - /// - /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// - public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) - { - return WaitForCompletion(ArmOperationHelpers.DefaultPollingInterval.Seconds, cancellationToken); - } - - /// - /// Waits for the completion of the long running operations. - /// - /// The polling interval in seconds to check for status. - /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// - public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) - { - while (true) - { - UpdateStatus(cancellationToken); - if (HasCompleted) - { - return Response.FromValue(Value, GetRawResponse()) as ArmResponse; - } - - Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); - } - } - } -} diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Utils/UtilityExtensions.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Utils/UtilityExtensions.cs index 975018e3666b..6d4321f16b87 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Utils/UtilityExtensions.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Utils/UtilityExtensions.cs @@ -43,7 +43,7 @@ public static IDictionary ReplaceWith(this IDictionary WaitForCompletion(this Operation operation, CancellationToken cancellationToken = default) { //TODO: Remove after ADO 5665 is closed - var pollingInterval = ArmOperationHelpers.DefaultPollingInterval; + var pollingInterval = OperationInternals.DefaultPollingInterval; while (true) { operation.UpdateStatus(cancellationToken); diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/ResourceGroupOperationsTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/ResourceGroupOperationsTests.cs index 379c2ff91826..51e8b349c248 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/ResourceGroupOperationsTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/ResourceGroupOperationsTests.cs @@ -31,7 +31,7 @@ public async Task StartDeleteRg() var rgOp = await Client.DefaultSubscription.GetResourceGroups().Construct(LocationData.WestUS2).StartCreateOrUpdateAsync(Recording.GenerateAssetName("testrg")); ResourceGroup rg = await rgOp.WaitForCompletionAsync(); var deleteOp = await rg.StartDeleteAsync(); - await deleteOp.WaitForCompletionAsync(); + await deleteOp.WaitForCompletionResponseAsync(); } [TestCase] From ec173e7349dd193e34413e8e03f018e746529d46 Mon Sep 17 00:00:00 2001 From: m-nash Date: Wed, 28 Apr 2021 18:56:58 -0700 Subject: [PATCH 10/15] address PR comments --- .../src/Operation/ArmOperation.cs | 35 +++++++------------ .../src/Operation/PhArmOperation.cs | 8 ++--- .../src/Operation/PhValueArmOperation.cs | 15 +++++--- .../src/Operation/PhVoidArmOperation.cs | 2 +- .../src/Response/ArmResponse.cs | 30 ++++++++++++++-- ...alueArmResponse.cs => ArmValueResponse.cs} | 12 ++++--- ...{VoidArmResponse.cs => ArmVoidResponse.cs} | 8 +++-- .../tests/Unit/ResourceTypeFilterTests.cs | 1 + 8 files changed, 70 insertions(+), 41 deletions(-) rename sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/{ValueArmResponse.cs => ArmValueResponse.cs} (57%) rename sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/{VoidArmResponse.cs => ArmVoidResponse.cs} (87%) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs index 7a122d69ca40..76f0509ab5a7 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/ArmOperation.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -23,32 +24,26 @@ protected ArmOperation() /// Waits for the completion of the long running operations. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// + /// The response with the final state of the operation. public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval, cancellationToken); } /// /// Waits for the completion of the long running operations. /// - /// The polling interval in seconds to check for status. + /// The polling interval to check for status. /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// - public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + /// The response with the final state of the operation. + public virtual Response WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { while (true) { UpdateStatus(cancellationToken); if (HasCompleted) { - return new VoidArmResponse(GetRawResponse()); + return new ArmVoidResponse(GetRawResponse()); } Task.Delay(pollingInterval, cancellationToken).Wait(cancellationToken); @@ -76,25 +71,19 @@ protected ArmOperation() /// Waits for the completion of the long running operations. /// /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// + /// The response with the final state of the operation. public virtual Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval, cancellationToken); } /// /// Waits for the completion of the long running operations. /// - /// The polling interval in seconds to check for status. + /// The polling interval to check for status. /// A token to allow the caller to cancel the call to the service. The default value is . - /// A response with the operation for this resource. - /// - /// Details on long running operation object. - /// - public virtual Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + /// The response with the final state of the operation. + public virtual Response WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { while (true) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index 16a2cf166f8d..a5ea7bdfd478 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -2,8 +2,6 @@ // Licensed under the MIT License. using System; -using System.Linq; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Azure.Core; @@ -11,7 +9,7 @@ namespace Azure.ResourceManager.Core { /// - /// A calss representing an arm operation wrapper object. + /// A class representing an arm operation wrapper object. /// /// The to convert TModel into. /// The model returned by existing Operation methods. @@ -118,11 +116,11 @@ public override async ValueTask> WaitForCompletionAsync(Ti /// public override Response WaitForCompletion(CancellationToken cancellationToken = default) { - return WaitForCompletion(OperationInternals.DefaultPollingInterval.Seconds, cancellationToken); + return WaitForCompletion(OperationInternals.DefaultPollingInterval, cancellationToken); } /// - public override Response WaitForCompletion(int pollingInterval, CancellationToken cancellationToken = default) + public override Response WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { while (true) { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs index 0edbf836167e..91d7a97836a2 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhValueArmOperation.cs @@ -9,7 +9,7 @@ namespace Azure.ResourceManager.Core { /// - /// A calss representing an arm operation wrapper object. + /// A class representing an arm operation wrapper object. /// internal class PhValueArmOperation : ArmOperation where TOperations : class @@ -17,10 +17,17 @@ internal class PhValueArmOperation : ArmOperation private readonly Operation _wrappedOperation; private readonly OperationOrResponseInternals _wrappedResponseOperation; + /// + /// Initializes a new instance of the class for mocking. + /// protected PhValueArmOperation() { } - + + /// + /// Initializes a new instance of the . + /// + /// The operation object to wrap. public PhValueArmOperation(Operation wrapped) { if (wrapped is null) @@ -30,9 +37,9 @@ public PhValueArmOperation(Operation wrapped) } /// - /// + /// Initializes a new instance of the . /// - /// + /// The response object to wrap. public PhValueArmOperation(Response wrapped) { if (wrapped is null) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs index 9bed6d9dbda1..23be0560b60d 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhVoidArmOperation.cs @@ -9,7 +9,7 @@ namespace Azure.ResourceManager.Core { /// - /// A calss representing an arm operation wrapper object. + /// A class representing an arm operation wrapper object. /// public class PhVoidArmOperation : ArmOperation { diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs index ebcfabfee872..f647cd14422b 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmResponse.cs @@ -26,7 +26,7 @@ public static ArmResponse FromValue(TOperations value, if (response is null) throw new ArgumentNullException(nameof(response)); - return new ValueArmResponse(response, value); + return new ArmValueResponse(response, value); } /// @@ -40,7 +40,20 @@ public static ArmResponse FromResponse(Response response) if (response is null) throw new ArgumentNullException(nameof(response)); - return new VoidArmResponse(response); + return new ArmVoidResponse(response); + } + + /// + /// Gets the correlation id from x-ms-correlation-id. + /// + public string CorrelationId + { + get + { + string correlationId = null; + Headers.TryGetValue("x-ms-correlation-id", out correlationId); + return correlationId; + } } } @@ -56,5 +69,18 @@ public abstract class ArmResponse : Response /// /// The instance. public static implicit operator TOperations(ArmResponse response) => response.Value; + + /// + /// Gets the correlation id from x-ms-correlation-id. + /// + public string CorrelationId + { + get + { + string correlationId = null; + GetRawResponse().Headers.TryGetValue("x-ms-correlation-id", out correlationId); + return correlationId; + } + } } } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmValueResponse.cs similarity index 57% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmValueResponse.cs index ab8ff5d5b71e..d3494f60cca7 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ValueArmResponse.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmValueResponse.cs @@ -2,17 +2,21 @@ // Licensed under the MIT License. using System; -using System.Collections.Generic; -using System.Text; namespace Azure.ResourceManager.Core { - internal class ValueArmResponse : ArmResponse + internal class ArmValueResponse : ArmResponse { private readonly ArmResponse _response; - public ValueArmResponse(ArmResponse response, TOperations value) + public ArmValueResponse(ArmResponse response, TOperations value) { + if (response is null) + throw new ArgumentNullException(nameof(response)); + + if (value is null) + throw new ArgumentNullException(nameof(value)); + _response = response; Value = value; } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmVoidResponse.cs similarity index 87% rename from sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs rename to sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmVoidResponse.cs index 2132289a559a..a1bdfd00e967 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/VoidArmResponse.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Response/ArmVoidResponse.cs @@ -1,18 +1,22 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.IO; using Azure.Core; namespace Azure.ResourceManager.Core { - internal class VoidArmResponse : ArmResponse + internal class ArmVoidResponse : ArmResponse { private readonly Response _response; - public VoidArmResponse(Response response) + public ArmVoidResponse(Response response) { + if (response is null) + throw new ArgumentNullException(nameof(response)); + _response = response; } diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs index ffe30846fa3b..7aa0b03b0063 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Unit/ResourceTypeFilterTests.cs @@ -13,6 +13,7 @@ public class ResourceTypeFilterTests [TestCase] public void TestResourceTypeFilterParamCheck() { + Assert.Throws(() => { new PhVoidArmOperation((Operation)null); }); Assert.Throws(() => { new PhVoidArmOperation((Response)null); }); } } From 5a9fff2f1b16058d87ce8b9feedef7dc7ae675b0 Mon Sep 17 00:00:00 2001 From: m-nash Date: Fri, 30 Apr 2021 10:49:13 -0700 Subject: [PATCH 11/15] update test classes to use new pattern --- .../tests/TestClients/ArmOperationTest.cs | 46 +++++++++---------- .../tests/TestClients/PhArmOperationTest.cs | 30 +++++++++++- .../TestClients/TestResourceOperations.cs | 19 ++++---- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs index fd0b1f67fe4b..82b28e5e9018 100644 --- a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs @@ -11,65 +11,61 @@ namespace Azure.Core.Tests { - public class ArmOperationTest : ArmOperation - where T : class + public class ArmOperationTest : ArmOperation, IOperationSource { - private T _value; + private TestResource _value; private bool _exceptionOnWait; + private OperationOrResponseInternals _operationHelper; protected ArmOperationTest() { } - public ArmOperationTest(T value, bool exceptionOnWait = false) + public ArmOperationTest(TestResource value, bool exceptionOnWait = false) { _value = value; _exceptionOnWait = exceptionOnWait; + _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, null)); } public override string Id => "testId"; - public override T Value => _value; + public override TestResource Value => _operationHelper.Value; - public override bool HasCompleted => true; + public override bool HasCompleted => _operationHelper.HasCompleted; - public override bool HasValue => true; + public override bool HasValue => _operationHelper.HasValue; - public override Response GetRawResponse() - { - return Response.FromValue(_value, null) as Response; - } + public override Response GetRawResponse() => _operationHelper.GetRawResponse(); - public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) + public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) { if (_exceptionOnWait) throw new ArgumentException("FakeArg"); - return new ValueTask>(Response.FromValue(_value, null)); + return new ValueTask>(Response.FromValue(_value, null)); } - public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) + public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) { if (_exceptionOnWait) throw new ArgumentException("FakeArg"); - return new ValueTask>(Response.FromValue(_value, null)); + return new ValueTask>(Response.FromValue(_value, null)); } - public override T CreateResult(Response response, CancellationToken cancellationToken) - { - if (_exceptionOnWait) - throw new ArgumentException("FakeArg"); + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatusAsync(cancellationToken); - return new ValueTask(Response.FromValue(_value, null) as Response); - } + public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatus(cancellationToken); - public async override ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + public TestResource CreateResult(Response response, CancellationToken cancellationToken) { - if (_exceptionOnWait) - throw new ArgumentException("FakeArg"); + return _value; + } - return Response.FromValue(_value, null) as Response; + public ValueTask CreateResultAsync(Response response, CancellationToken cancellationToken) + { + return new ValueTask(_value); } } } diff --git a/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs index a87d98ce67a8..a174827c4cdf 100644 --- a/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs @@ -1,17 +1,43 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.ResourceManager.Core; + namespace Azure.Core.Tests { - public class PhArmOperationTest : ArmOperationTest + public class PhArmOperationTest : ArmOperation where T : class { + private OperationOrResponseInternals _operationHelper; + + public override T Value => _operationHelper.Value; + + public override bool HasValue => _operationHelper.HasValue; + + public override string Id => "MyId"; + + public override bool HasCompleted => _operationHelper.HasCompleted; + protected PhArmOperationTest() { } - public PhArmOperationTest(T value) : base(value) + public PhArmOperationTest(T value) { + _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, null)); } + + public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) => _operationHelper.WaitForCompletionAsync(cancellationToken); + + public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) => _operationHelper.WaitForCompletionAsync(pollingInterval, cancellationToken); + + public override Response GetRawResponse() => _operationHelper.GetRawResponse(); + + public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatusAsync(cancellationToken); + + public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatus(cancellationToken); } } diff --git a/sdk/core/Azure.Core/tests/TestClients/TestResourceOperations.cs b/sdk/core/Azure.Core/tests/TestClients/TestResourceOperations.cs index 46b5116c1844..f49ac25bf2cc 100644 --- a/sdk/core/Azure.Core/tests/TestClients/TestResourceOperations.cs +++ b/sdk/core/Azure.Core/tests/TestClients/TestResourceOperations.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core.Pipeline; +using Azure.ResourceManager.Core; namespace Azure.Core.Tests { @@ -17,14 +18,14 @@ public virtual TestResourceOperations GetAnotherOperations() return new TestResource(); } - public virtual ArmOperationTest GetArmOperation(bool exceptionOnWait = false, CancellationToken cancellationToken = default) + public virtual ArmOperationTest GetArmOperation(bool exceptionOnWait = false, CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetArmOperation"); scope.Start(); try { - return new ArmOperationTest(new TestResource(), exceptionOnWait); + return new ArmOperationTest(new TestResource(), exceptionOnWait); } catch (Exception e) { @@ -33,14 +34,14 @@ public virtual ArmOperationTest GetArmOperation(bool exceptionOnWa } } - public virtual Task> GetArmOperationAsync(bool exceptionOnWait = false, CancellationToken cancellationToken = default) + public virtual Task GetArmOperationAsync(bool exceptionOnWait = false, CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetArmOperation"); scope.Start(); try { - return Task.FromResult(new ArmOperationTest(new TestResource(), exceptionOnWait)); + return Task.FromResult(new ArmOperationTest(new TestResource(), exceptionOnWait)); } catch (Exception e) { @@ -81,7 +82,7 @@ public virtual Task> GetArmResponseAsync(Cancellat } } - public virtual ArmOperationTest GetPhArmOperation(CancellationToken cancellationToken = default) + public virtual ArmOperation GetPhArmOperation(CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetPhArmOperation"); scope.Start(); @@ -97,14 +98,14 @@ public virtual ArmOperationTest GetPhArmOperation(CancellationToke } } - public virtual Task> GetPhArmOperationAsync(CancellationToken cancellationToken = default) + public virtual Task> GetPhArmOperationAsync(CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetPhArmOperation"); scope.Start(); try { - return Task.FromResult>(new PhArmOperationTest(new TestResource())); + return Task.FromResult>(new PhArmOperationTest(new TestResource())); } catch (Exception e) { @@ -177,7 +178,7 @@ public virtual Task> GetArmResponseExceptionAsync( } } - public virtual ArmOperationTest GetArmOperationException(CancellationToken cancellationToken = default) + public virtual ArmOperationTest GetArmOperationException(CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetArmOperationException"); scope.Start(); @@ -193,7 +194,7 @@ public virtual ArmOperationTest GetArmOperationException(Cancellat } } - public virtual Task> GetArmOperationExceptionAsync(CancellationToken cancellationToken = default) + public virtual Task GetArmOperationExceptionAsync(CancellationToken cancellationToken = default) { using var scope = _diagnostic.CreateScope("TestResourceOperations.GetArmOperationException"); scope.Start(); From cd712bba9d30822e0116c0df88bb60a595c279e5 Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 4 May 2021 19:54:18 -0700 Subject: [PATCH 12/15] final fixes for arm core tests --- .../src/Operation/PhArmOperation.cs | 9 ++++----- .../tests/Scenario/GenericResourceTests.cs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs index a5ea7bdfd478..b0f9777dd927 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/src/Operation/PhArmOperation.cs @@ -106,11 +106,10 @@ public override async ValueTask> WaitForCompletionAsync(Ca /// public override async ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) { - var task = _doesWrapOperation - ? _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken) - : _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken); - var value = await task.ConfigureAwait(false); - return Response.FromValue(_converter(value), GetRawResponse()); + var value = _doesWrapOperation + ? await _wrappedOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false) + : await _wrappedResponseOperation.WaitForCompletionAsync(pollingInterval, cancellationToken).ConfigureAwait(false); + return Response.FromValue(_converter(value.Value), GetRawResponse()); } /// diff --git a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/GenericResourceTests.cs b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/GenericResourceTests.cs index 413d52b711df..e2d08c7557dc 100644 --- a/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/GenericResourceTests.cs +++ b/sdk/resourcemanager/Azure.ResourceManager.Core/tests/Scenario/GenericResourceTests.cs @@ -26,7 +26,7 @@ public async Task LocalOneTimeSetup() { _rgName = SessionRecording.GenerateAssetName("testRg-"); var subscription = await GlobalClient.GetSubscriptions().TryGetAsync(SessionEnvironment.SubscriptionId); - _ = subscription.GetResourceGroups().Construct(_location).StartCreateOrUpdateAsync(_rgName).ConfigureAwait(false).GetAwaiter().GetResult().Value; + _ = await subscription.GetResourceGroups().Construct(_location).StartCreateOrUpdateAsync(_rgName).ConfigureAwait(false); StopSessionRecording(); } From 8649b18fc312ee350b9f1288c4c61ffb6a76d7b6 Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 4 May 2021 20:02:05 -0700 Subject: [PATCH 13/15] use mock response instead of null --- .../Azure.Core/tests/TestClients/ArmOperationTest.cs | 10 ++++------ .../Azure.Core/tests/TestClients/PhArmOperationTest.cs | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs index 82b28e5e9018..39f8e95a9ca5 100644 --- a/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/ArmOperationTest.cs @@ -2,11 +2,9 @@ // Licensed under the MIT License. using System; -using System.Linq; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Azure.Core; +using Azure.Core.TestFramework; using Azure.ResourceManager.Core; namespace Azure.Core.Tests @@ -25,7 +23,7 @@ public ArmOperationTest(TestResource value, bool exceptionOnWait = false) { _value = value; _exceptionOnWait = exceptionOnWait; - _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, null)); + _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, new MockResponse(200))); } public override string Id => "testId"; @@ -43,7 +41,7 @@ public override ValueTask> WaitForCompletionAsync(Cancell if (_exceptionOnWait) throw new ArgumentException("FakeArg"); - return new ValueTask>(Response.FromValue(_value, null)); + return new ValueTask>(Response.FromValue(_value, new MockResponse(200))); } public override ValueTask> WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken) @@ -51,7 +49,7 @@ public override ValueTask> WaitForCompletionAsync(TimeSpa if (_exceptionOnWait) throw new ArgumentException("FakeArg"); - return new ValueTask>(Response.FromValue(_value, null)); + return new ValueTask>(Response.FromValue(_value, new MockResponse(200))); } public override ValueTask UpdateStatusAsync(CancellationToken cancellationToken = default) => _operationHelper.UpdateStatusAsync(cancellationToken); diff --git a/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs b/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs index a174827c4cdf..a70a99bc5910 100644 --- a/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs +++ b/sdk/core/Azure.Core/tests/TestClients/PhArmOperationTest.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Azure.Core.TestFramework; using Azure.ResourceManager.Core; namespace Azure.Core.Tests @@ -27,7 +28,7 @@ protected PhArmOperationTest() public PhArmOperationTest(T value) { - _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, null)); + _operationHelper = new OperationOrResponseInternals(Response.FromValue(value, new MockResponse(200))); } public override ValueTask> WaitForCompletionAsync(CancellationToken cancellationToken = default) => _operationHelper.WaitForCompletionAsync(cancellationToken); From 09bb02b40e130e72652281b9dd79306a2128fdff Mon Sep 17 00:00:00 2001 From: m-nash Date: Tue, 4 May 2021 20:17:47 -0700 Subject: [PATCH 14/15] updates to proto code --- .../compute/RollingUpgradeOperations.cs | 8 ++++---- .../compute/VirtualMachineScaleSetOperations.cs | 16 ++++++++-------- .../network/LoadBalancerOperations.cs | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs b/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs index 8d6dbc2c239d..980921f3de9b 100644 --- a/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs +++ b/sdk/resourcemanager/Proto.Client/compute/RollingUpgradeOperations.cs @@ -60,16 +60,16 @@ await Operations.GetLatestAsync(ParentId.ResourceGroupName, ParentId.Name, cance // Note: Singleton may have different operations such as GET/PUT/PATCH/POST or a combination of these // Individual methods will be generated as they are declared - public ArmResponse Cancel(CancellationToken cancellationToken = default) + public ArmResponse Cancel(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations + return ArmResponse.FromResponse(Operations .StartCancel(ParentId.ResourceGroupName, ParentId.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } - public async Task> CancelAsync(CancellationToken cancellationToken = default) + public async Task CancelAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations + return ArmResponse.FromResponse((await Operations .StartCancel(ParentId.ResourceGroupName, ParentId.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken))); } diff --git a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs index d7425a1130c0..dae66829ac4d 100644 --- a/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs +++ b/sdk/resourcemanager/Proto.Client/compute/VirtualMachineScaleSetOperations.cs @@ -70,27 +70,27 @@ public static VirtualMachineScaleSetOperations FromGeneric(GenericResourceOperat } /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)).WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// diff --git a/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs b/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs index 2994fa8f1e50..4f42ffe004a7 100644 --- a/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs +++ b/sdk/resourcemanager/Proto.Client/network/LoadBalancerOperations.cs @@ -49,30 +49,30 @@ protected LoadBalancerOperations(ResourceOperationsBase options, ResourceIdentif ClientOptions.Convert()).LoadBalancers; /// - public ArmResponse Delete(CancellationToken cancellationToken = default) + public ArmResponse Delete(CancellationToken cancellationToken = default) { - return new ArmResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) + return ArmResponse.FromResponse(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public async Task> DeleteAsync(CancellationToken cancellationToken = default) + public async Task DeleteAsync(CancellationToken cancellationToken = default) { - return new ArmResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) + return ArmResponse.FromResponse((await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)) .WaitForCompletionAsync(cancellationToken).ConfigureAwait(false).GetAwaiter().GetResult()); } /// - public ArmOperation StartDelete(CancellationToken cancellationToken = default) + public ArmOperation StartDelete(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(Operations.StartDelete(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// - public async Task> StartDeleteAsync(CancellationToken cancellationToken = default) + public async Task StartDeleteAsync(CancellationToken cancellationToken = default) { - return new ArmVoidOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); + return new PhVoidArmOperation(await Operations.StartDeleteAsync(Id.ResourceGroupName, Id.Name, cancellationToken)); } /// From f888e327ef3894d86b5ae649406bb1f2240bb01f Mon Sep 17 00:00:00 2001 From: m-nash Date: Wed, 5 May 2021 10:26:17 -0700 Subject: [PATCH 15/15] add null check around basetype --- .../src/Instrumentation/InstrumentResultInterceptor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/core/Azure.Core.TestFramework/src/Instrumentation/InstrumentResultInterceptor.cs b/sdk/core/Azure.Core.TestFramework/src/Instrumentation/InstrumentResultInterceptor.cs index f5de30d6bbcb..1c94317d018f 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Instrumentation/InstrumentResultInterceptor.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Instrumentation/InstrumentResultInterceptor.cs @@ -41,7 +41,7 @@ public void Intercept(IInvocation invocation) if ( // Generated ARM clients will have a property containing the sub-client that ends with Operations. - (invocation.Method.Name.StartsWith("get_") && (type.Name.EndsWith("Operations") || type.BaseType.Name.EndsWith("Operations"))) || + (invocation.Method.Name.StartsWith("get_") && (type.Name.EndsWith("Operations") || (type.BaseType != null && type.BaseType.Name.EndsWith("Operations")))) || // Instrument the container construction methods inside Operations objects (invocation.Method.Name.StartsWith("Get") && type.Name.EndsWith("Container")) || // Instrument the operations construction methods inside Operations objects