-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* intial set-up for llc tests * don't generate the code * saving work in progress * remove edits to Core * simplify tests * implement LLC method with mock transport * Add in basic model cast functionality, without new Core features * intial approach * use ReqOpts to get default classifier functionality and do ro.Apply() * simplify RequestOptions API; experiment with generating classifiers directly * update statusoptions value names and add tests * handle null options * update api listing * add IsError to PipelineResponse * move logic to pipeline * undo changes to experimental * update Core API listing and undo changes to experimental * add tests * await pipeline call * initial move changes to Experimental * api tweaks * Add ClassfiedResponse wrapping Response with IsError * update api listing * api tweaks * pr fb
- Loading branch information
1 parent
1c028c5
commit 57f3d50
Showing
5 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
sdk/core/Azure.Core.Experimental/src/ClassifiedResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.IO; | ||
using System.Text; | ||
|
||
namespace Azure.Core | ||
{ | ||
/// <summary> | ||
/// Wrap Response and add IsError field. | ||
/// </summary> | ||
public class ClassifiedResponse : Response | ||
{ | ||
private bool _disposed; | ||
|
||
private Response Response { get; } | ||
|
||
/// <summary> | ||
/// </summary> | ||
public bool IsError { get; private set; } | ||
|
||
internal void EvaluateError(HttpMessage message) | ||
{ | ||
IsError = message.ResponseClassifier.IsErrorResponse(message); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override int Status => Response.Status; | ||
/// <inheritdoc /> | ||
public override string ReasonPhrase => Response.ReasonPhrase; | ||
/// <inheritdoc /> | ||
public override Stream? ContentStream { get => Response.ContentStream; set => Response.ContentStream = value; } | ||
/// <inheritdoc /> | ||
public override string ClientRequestId { get => Response.ClientRequestId; set => Response.ClientRequestId = value; } | ||
/// <inheritdoc /> | ||
protected override bool TryGetHeader(string name, [NotNullWhen(true)] out string? value) => Response.Headers.TryGetValue(name, out value); | ||
/// <inheritdoc /> | ||
protected override bool TryGetHeaderValues(string name, [NotNullWhen(true)] out IEnumerable<string>? values) => Response.Headers.TryGetValues(name, out values); | ||
/// <inheritdoc /> | ||
protected override bool ContainsHeader(string name) => Response.Headers.Contains(name); | ||
/// <inheritdoc /> | ||
protected override IEnumerable<HttpHeader> EnumerateHeaders() => Response.Headers; | ||
|
||
/// <summary> | ||
/// Represents a result of Azure operation with a <see cref="JsonData"/> response. | ||
/// </summary> | ||
/// <param name="response">The response returned by the service.</param> | ||
public ClassifiedResponse(Response response) | ||
{ | ||
Response = response; | ||
} | ||
|
||
/// <summary> | ||
/// Frees resources held by the <see cref="DynamicResponse"/> object. | ||
/// </summary> | ||
public override void Dispose() | ||
{ | ||
Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
/// <summary> | ||
/// Frees resources held by the <see cref="DynamicResponse"/> object. | ||
/// </summary> | ||
/// <param name="disposing">true if we should dispose, otherwise false</param> | ||
protected virtual void Dispose(bool disposing) | ||
{ | ||
if (_disposed) | ||
{ | ||
return; | ||
} | ||
if (disposing) | ||
{ | ||
Response.Dispose(); | ||
} | ||
_disposed = true; | ||
} | ||
|
||
private string DebuggerDisplay | ||
{ | ||
get => $"{{Status: {Response.Status}, IsError: {IsError}}}"; | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
sdk/core/Azure.Core.Experimental/src/ResponseExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
#nullable disable | ||
|
||
using System; | ||
|
||
namespace Azure.Core.Pipeline | ||
{ | ||
/// <summary> | ||
/// Extensions for experimenting with Response API. | ||
/// </summary> | ||
public static class ResponseExtensions | ||
{ | ||
/// <summary> | ||
/// This will be a property on the non-experimental Azure.Core.Response. | ||
/// </summary> | ||
/// <param name="response"></param> | ||
/// <returns></returns> | ||
public static bool IsError(this Response response) | ||
{ | ||
var classifiedResponse = response as ClassifiedResponse; | ||
|
||
if (classifiedResponse == null) | ||
{ | ||
throw new InvalidOperationException("IsError was not set on the response. " + | ||
"Please ensure the pipeline includes ResponsePropertiesPolicy."); | ||
} | ||
|
||
return classifiedResponse.IsError; | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
sdk/core/Azure.Core.Experimental/src/ResponsePropertiesPolicy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using Azure.Core.Pipeline; | ||
|
||
namespace Azure.Core | ||
{ | ||
/// <summary> | ||
/// </summary> | ||
internal class ResponsePropertiesPolicy : HttpPipelinePolicy | ||
{ | ||
/// <inheritdoc/> | ||
public override void Process(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline) | ||
{ | ||
ProcessAsync(message, pipeline, false).EnsureCompleted(); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline) | ||
{ | ||
return ProcessAsync(message, pipeline, true); | ||
} | ||
|
||
private static async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline, bool async) | ||
{ | ||
if (async) | ||
{ | ||
await ProcessNextAsync(message, pipeline).ConfigureAwait(false); | ||
} | ||
else | ||
{ | ||
ProcessNext(message, pipeline); | ||
} | ||
|
||
// In the non-experimental version of this policy, these lines reduce to: | ||
// > message.Response.EvaluateError(message); | ||
ClassifiedResponse response = new ClassifiedResponse(message.Response); | ||
response.EvaluateError(message); | ||
message.Response = response; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Text.Json; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Azure.Core.Experimental; | ||
using Azure.Core.Experimental.Tests; | ||
using Azure.Core.Experimental.Tests.Models; | ||
using Azure.Core.Pipeline; | ||
using Azure.Core.TestFramework; | ||
using NUnit.Framework; | ||
|
||
namespace Azure.Core.Tests | ||
{ | ||
public class PipelineTests : ClientTestBase | ||
{ | ||
public PipelineTests(bool isAsync) : base(isAsync) | ||
{ | ||
} | ||
|
||
[Test] | ||
public async Task PipelineSetsResponseIsErrorTrue() | ||
{ | ||
var mockTransport = new MockTransport( | ||
new MockResponse(500)); | ||
|
||
var pipeline = new HttpPipeline(mockTransport, new[] { new ResponsePropertiesPolicy() }); | ||
|
||
Request request = pipeline.CreateRequest(); | ||
request.Method = RequestMethod.Get; | ||
request.Uri.Reset(new Uri("https://contoso.a.io")); | ||
Response response = await pipeline.SendRequestAsync(request, CancellationToken.None); | ||
|
||
Assert.IsTrue(response.IsError()); | ||
} | ||
|
||
[Test] | ||
public async Task PipelineSetsResponseIsErrorFalse() | ||
{ | ||
var mockTransport = new MockTransport( | ||
new MockResponse(200)); | ||
|
||
var pipeline = new HttpPipeline(mockTransport, new[] { new ResponsePropertiesPolicy() }); | ||
|
||
Request request = pipeline.CreateRequest(); | ||
request.Method = RequestMethod.Get; | ||
request.Uri.Reset(new Uri("https://contoso.a.io")); | ||
Response response = await pipeline.SendRequestAsync(request, CancellationToken.None); | ||
|
||
Assert.IsFalse(response.IsError()); | ||
} | ||
|
||
[Test] | ||
public async Task CustomClassifierSetsResponseIsError() | ||
{ | ||
var mockTransport = new MockTransport( | ||
new MockResponse(404)); | ||
|
||
var pipeline = new HttpPipeline(mockTransport, | ||
new[] { new ResponsePropertiesPolicy() }, | ||
new CustomResponseClassifier()); | ||
|
||
Request request = pipeline.CreateRequest(); | ||
request.Method = RequestMethod.Get; | ||
request.Uri.Reset(new Uri("https://contoso.a.io")); | ||
Response response = await pipeline.SendRequestAsync(request, CancellationToken.None); | ||
|
||
Assert.IsFalse(response.IsError()); | ||
} | ||
|
||
private class CustomResponseClassifier : ResponseClassifier | ||
{ | ||
public override bool IsRetriableResponse(HttpMessage message) | ||
{ | ||
return message.Response.Status == 500; | ||
} | ||
|
||
public override bool IsRetriableException(Exception exception) | ||
{ | ||
return false; | ||
} | ||
|
||
public override bool IsErrorResponse(HttpMessage message) | ||
{ | ||
return IsRetriableResponse(message); | ||
} | ||
} | ||
} | ||
} |