< Summary

Class:Azure.AI.FormRecognizer.Training.TrainingOperation
Assembly:Azure.AI.FormRecognizer
File(s):C:\Git\azure-sdk-for-net\sdk\formrecognizer\Azure.AI.FormRecognizer\src\TrainingOperation.cs
Covered lines:45
Uncovered lines:2
Coverable lines:47
Total lines:202
Line coverage:95.7% (45 of 47)
Covered branches:11
Total branches:12
Branch coverage:91.6% (11 of 12)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
get_Id()-100%100%
get_Value()-100%100%
get_HasCompleted()-100%100%
get_HasValue()-100%100%
GetRawResponse()-100%100%
WaitForCompletionAsync(...)-0%100%
WaitForCompletionAsync(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
UpdateStatus(...)-0%100%
UpdateStatusAsync()-100%100%
UpdateStatusAsync()-100%87.5%

File(s)

C:\Git\azure-sdk-for-net\sdk\formrecognizer\Azure.AI.FormRecognizer\src\TrainingOperation.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Linq;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using Azure.AI.FormRecognizer.Models;
 9using Azure.Core;
 10using Azure.Core.Pipeline;
 11
 12namespace Azure.AI.FormRecognizer.Training
 13{
 14    /// <summary>
 15    /// Tracks the status of a long-running operation for training a model from a collection of custom forms.
 16    /// </summary>
 17    public class TrainingOperation : Operation<CustomFormModel>
 18    {
 19        /// <summary>Provides communication with the Form Recognizer Azure Cognitive Service through its REST API.</summ
 20        private readonly ServiceRestClient _serviceClient;
 21
 22        /// <summary>Provides tools for exception creation in case of failure.</summary>
 23        private readonly ClientDiagnostics _diagnostics;
 24
 25        private RequestFailedException _requestFailedException;
 26
 27        /// <summary>The last HTTP response received from the server. <c>null</c> until the first response is received.<
 28        private Response _response;
 29
 30        /// <summary>The result of the long-running operation. <c>null</c> until result is received on status update.</s
 31        private CustomFormModel _value;
 32
 33        /// <summary><c>true</c> if the long-running operation has completed. Otherwise, <c>false</c>.</summary>
 34        private bool _hasCompleted;
 35
 36        /// <summary>
 37        /// Gets an ID representing the operation that can be used to poll for the status
 38        /// of the long-running operation.
 39        /// </summary>
 105840        public override string Id { get; }
 41
 42        /// <summary>
 43        /// Final result of the long-running operation.
 44        /// </summary>
 45        /// <remarks>
 46        /// This property can be accessed only after the operation completes successfully (HasValue is true).
 47        /// </remarks>
 48        public override CustomFormModel Value
 49        {
 50            get
 51            {
 36052                if (HasCompleted && !HasValue)
 53#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations
 454                    throw _requestFailedException;
 55#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations
 56                else
 35657                    return OperationHelpers.GetValue(ref _value);
 58            }
 59        }
 60
 61        /// <summary>
 62        /// Returns true if the long-running operation completed.
 63        /// </summary>
 140264        public override bool HasCompleted => _hasCompleted;
 65
 66        /// <summary>
 67        /// Returns true if the long-running operation completed successfully and has produced final result (accessible 
 68        /// </summary>
 49269        public override bool HasValue => _value != null;
 70
 71        /// <summary>
 72        /// The last HTTP response received from the server.
 73        /// </summary>
 74        /// <remarks>
 75        /// The last response returned from the server during the lifecycle of this instance.
 76        /// An instance of <see cref="TrainingOperation"/> sends requests to a server in UpdateStatusAsync, UpdateStatus
 77        /// Responses from these requests can be accessed using GetRawResponse.
 78        /// </remarks>
 117879        public override Response GetRawResponse() => _response;
 80
 81        /// <summary>
 82        /// Periodically calls the server till the long-running operation completes.
 83        /// </summary>
 84        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the periodical service calls.</pa
 85        /// <returns>The last HTTP response received from the server.</returns>
 86        /// <remarks>
 87        /// This method will periodically call UpdateStatusAsync till HasCompleted is true, then return the final result
 88        /// </remarks>
 89        public override ValueTask<Response<CustomFormModel>> WaitForCompletionAsync(CancellationToken cancellationToken 
 090            this.DefaultWaitForCompletionAsync(cancellationToken);
 91
 92        /// <summary>
 93        /// Periodically calls the server till the long-running operation completes.
 94        /// </summary>
 95        /// <param name="pollingInterval">
 96        /// The interval between status requests to the server.
 97        /// The interval can change based on information returned from the server.
 98        /// For example, the server might communicate to the client that there is not reason to poll for status change s
 99        /// </param>
 100        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the periodical service calls.</pa
 101        /// <returns>The last HTTP response received from the server.</returns>
 102        /// <remarks>
 103        /// This method will periodically call UpdateStatusAsync till HasCompleted is true, then return the final result
 104        /// </remarks>
 105        public override ValueTask<Response<CustomFormModel>> WaitForCompletionAsync(TimeSpan pollingInterval, Cancellati
 140106            this.DefaultWaitForCompletionAsync(pollingInterval, cancellationToken);
 107
 148108        internal TrainingOperation(string location, ServiceRestClient allOperations, ClientDiagnostics diagnostics)
 109        {
 148110            _serviceClient = allOperations;
 148111            _diagnostics = diagnostics;
 112
 113            // TODO: validate this
 114            // https://github.com/Azure/azure-sdk-for-net/issues/10385
 148115            Id = location.Split('/').Last();
 148116        }
 117
 118        /// <summary>
 119        /// Initializes a new instance of the <see cref="TrainingOperation"/> class.
 120        /// </summary>
 121        /// <param name="operationId">The ID of this operation.</param>
 122        /// <param name="client">The client used to check for completion.</param>
 8123        public TrainingOperation(string operationId, FormTrainingClient client)
 124        {
 8125            Id = operationId;
 8126            _diagnostics = client.Diagnostics;
 8127            _serviceClient = client.ServiceClient;
 8128        }
 129
 130        /// <summary>
 131        /// Calls the server to get updated status of the long-running operation.
 132        /// </summary>
 133        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the service call.</param>
 134        /// <returns>The HTTP response received from the server.</returns>
 135        /// <remarks>
 136        /// This operation will update the value returned from GetRawResponse and might update HasCompleted, HasValue, a
 137        /// </remarks>
 138        public override Response UpdateStatus(CancellationToken cancellationToken = default) =>
 0139            UpdateStatusAsync(false, cancellationToken).EnsureCompleted();
 140
 141        /// <summary>
 142        /// Calls the server to get updated status of the long-running operation.
 143        /// </summary>
 144        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the service call.</param>
 145        /// <returns>The HTTP response received from the server.</returns>
 146        /// <remarks>
 147        /// This operation will update the value returned from GetRawResponse and might update HasCompleted, HasValue, a
 148        /// </remarks>
 149        public override async ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) =>
 1054150            await UpdateStatusAsync(true, cancellationToken).ConfigureAwait(false);
 151
 152        /// <summary>
 153        /// Calls the server to get updated status of the long-running operation.
 154        /// </summary>
 155        /// <param name="async">When <c>true</c>, the method will be executed asynchronously; otherwise, it will execute
 156        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used for the service call.</param>
 157        /// <returns>The HTTP response received from the server.</returns>
 158        private async ValueTask<Response> UpdateStatusAsync(bool async, CancellationToken cancellationToken)
 159        {
 1054160            if (!_hasCompleted)
 161            {
 1054162                using DiagnosticScope scope = _diagnostics.CreateScope($"{nameof(TrainingOperation)}.{nameof(UpdateStatu
 1054163                scope.Start();
 164
 165                try
 166                {
 167                    // Include keys is always set to true -- the service does not have a use case for includeKeys: false
 1054168                    Response<Model> update = async
 1054169                        ? await _serviceClient.GetCustomModelAsync(new Guid(Id), includeKeys: true, cancellationToken).C
 1054170                        : _serviceClient.GetCustomModel(new Guid(Id), includeKeys: true, cancellationToken);
 171
 1054172                    _response = update.GetRawResponse();
 173
 1054174                    if (update.Value.ModelInfo.Status == CustomFormModelStatus.Ready)
 175                    {
 176                        // We need to first assign a value and then mark the operation as completed to avoid a race cond
 132177                        _value = new CustomFormModel(update.Value);
 132178                        _hasCompleted = true;
 179                    }
 922180                    else if (update.Value.ModelInfo.Status == CustomFormModelStatus.Invalid)
 181                    {
 8182                        _requestFailedException = await ClientCommon.CreateExceptionForFailedOperationAsync(
 8183                                                        async,
 8184                                                        _diagnostics,
 8185                                                        _response,
 8186                                                        update.Value.TrainResult.Errors,
 8187                                                        $"Invalid model created with ID {update.Value.ModelInfo.ModelId}
 8188                        _hasCompleted = true;
 8189                        throw _requestFailedException;
 190                    }
 1046191                }
 8192                catch (Exception e)
 193                {
 8194                    scope.Failed(e);
 8195                    throw;
 196                }
 1046197            }
 198
 1046199            return GetRawResponse();
 1046200        }
 201    }
 202}