Skip to content

Commit

Permalink
Refactoring responses (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevejgordon authored Nov 10, 2022
1 parent 38d8f54 commit 0f7b402
Show file tree
Hide file tree
Showing 15 changed files with 38 additions and 60 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>

Expand All @@ -10,7 +10,7 @@
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<IsPackable>False</IsPackable>

<CheckEolTargetFramework>false</CheckEolTargetFramework>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>$(SolutionRoot)\build\keys\keypair.snk</AssemblyOriginatorKeyFile>

Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "6.0.202",
"version": "6.0.403",
"rollForward": "latestFeature",
"allowPrerelease": false
}
Expand Down
4 changes: 2 additions & 2 deletions src/Elastic.Transport.VirtualizedCluster/Audit/Auditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public async Task<Auditor> TraceElasticsearchExceptionOnResponse(ClientCall call
Action call = () => { Response = _cluster.ClientCall(callTrace?.RequestOverrides); };
call();

if (Response.ApiCallDetails.Success) throw new Exception("Expected call to not be valid");
if (Response.ApiCallDetails.HasSuccessfulStatusCode) throw new Exception("Expected call to not be valid");

if (Response.ApiCallDetails.OriginalException is not TransportException exception)
throw new Exception("OriginalException on response is not expected TransportException");
Expand All @@ -142,7 +142,7 @@ public async Task<Auditor> TraceElasticsearchExceptionOnResponse(ClientCall call
_clusterAsync.ClientThrows(false);
Func<Task> callAsync = async () => { ResponseAsync = await _clusterAsync.ClientCallAsync(callTrace?.RequestOverrides).ConfigureAwait(false); };
await callAsync().ConfigureAwait(false);
if (Response.ApiCallDetails.Success) throw new Exception("Expected call to not be valid");
if (Response.ApiCallDetails.HasSuccessfulStatusCode) throw new Exception("Expected call to not be valid");
exception = ResponseAsync.ApiCallDetails.OriginalException as TransportException;
if (exception == null) throw new Exception("OriginalException on response is not expected TransportException");
assert(exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public override TResponse CallProductEndpoint<TResponse>(RequestData requestData
apiCallDetails.AuditTrail = AuditTrail;

ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails, response);
if (!response.ApiCallDetails.Success) audit.Event = requestData.OnFailureAuditEvent;
if (!response.ApiCallDetails.HasSuccessfulStatusCode) audit.Event = requestData.OnFailureAuditEvent;
return response;
}
catch (Exception e)
Expand Down Expand Up @@ -215,7 +215,7 @@ public override async Task<TResponse> CallProductEndpointAsync<TResponse>(Reques
apiCallDetails.AuditTrail = AuditTrail;

ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails, response);
if (!response.ApiCallDetails.Success) audit.Event = requestData.OnFailureAuditEvent;
if (!response.ApiCallDetails.HasSuccessfulStatusCode) audit.Event = requestData.OnFailureAuditEvent;
return response;
}
catch (Exception e)
Expand All @@ -230,7 +230,7 @@ public override async Task<TResponse> CallProductEndpointAsync<TResponse>(Reques
public override TransportException CreateClientException<TResponse>(
TResponse response, ApiCallDetails callDetails, RequestData data, List<PipelineException> pipelineExceptions)
{
if (callDetails?.Success ?? false) return null;
if (callDetails?.HasSuccessfulStatusCode ?? false) return null;

var pipelineFailure = data.OnFailurePipelineFailure;
var innerException = callDetails?.OriginalException;
Expand Down Expand Up @@ -424,7 +424,7 @@ public override void Ping(Node node)
d.EndState = response.ApiCallDetails;
ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails);
//ping should not silently accept bad but valid http responses
if (!response.ApiCallDetails.Success)
if (!response.ApiCallDetails.HasSuccessfulStatusCode)
throw new PipelineException(pingData.OnFailurePipelineFailure, response.ApiCallDetails.OriginalException) { Response = response };
}
catch (Exception e)
Expand Down Expand Up @@ -454,7 +454,7 @@ public override async Task PingAsync(Node node, CancellationToken cancellationTo
d.EndState = response.ApiCallDetails;
ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails);
//ping should not silently accept bad but valid http responses
if (!response.ApiCallDetails.Success)
if (!response.ApiCallDetails.HasSuccessfulStatusCode)
throw new PipelineException(pingData.OnFailurePipelineFailure, response.ApiCallDetails.OriginalException) { Response = response };
}
catch (Exception e)
Expand Down Expand Up @@ -488,7 +488,7 @@ public override void Sniff()

ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails);
//sniff should not silently accept bad but valid http responses
if (!response.ApiCallDetails.Success)
if (!response.ApiCallDetails.HasSuccessfulStatusCode)
throw new PipelineException(requestData.OnFailurePipelineFailure, response.ApiCallDetails.OriginalException) { Response = response };

_nodePool.Reseed(nodes);
Expand Down Expand Up @@ -528,7 +528,7 @@ public override async Task SniffAsync(CancellationToken cancellationToken)

ThrowBadAuthPipelineExceptionWhenNeeded(response.ApiCallDetails);
//sniff should not silently accept bad but valid http responses
if (!response.ApiCallDetails.Success)
if (!response.ApiCallDetails.HasSuccessfulStatusCode)
throw new PipelineException(requestData.OnFailurePipelineFailure, response.ApiCallDetails.OriginalException) { Response = response };

_nodePool.Reseed(nodes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ IReadOnlyDictionary<TcpState, int> tcpStats

var details = new ApiCallDetails
{
Success = success,
HasSuccessfulStatusCode = success,
OriginalException = exception,
HttpStatusCode = statusCode,
RequestBodyInBytes = requestData.PostData?.WrittenBytes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public interface ITransportConfiguration : IDisposable
UserAgent UserAgent { get; }

/// <summary>
/// Allow you to override the status code inspection that sets <see cref="ApiCallDetails.Success"/>
/// Allow you to override the status code inspection that sets <see cref="ApiCallDetails.HasSuccessfulStatusCode"/>
/// <para>
/// Defaults to validating the statusCode is greater or equal to 200 and less then 300
/// </para>
Expand Down
2 changes: 2 additions & 0 deletions src/Elastic.Transport/Elastic.Transport.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
<ItemGroup>
<InternalsVisibleTo Include="Elastic.Transport.VirtualizedCluster" Key="$(ExposedPublicKey)" />
<InternalsVisibleTo Include="Elastic.Transport.Tests" Key="$(ExposedPublicKey)" />
<InternalsVisibleTo Include="Elastic.Transport.Benchmarks" Key="$(ExposedPublicKey)" />
<InternalsVisibleTo Include="Elastic.Transport.IntegrationTests" Key="$(ExposedPublicKey)" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,16 @@ public IEnumerable<string> ElasticsearchWarnings
/// <summary>
///
/// </summary>
/// <returns></returns>
[JsonIgnore]
public string DebugInformation
{
get
{
var sb = new StringBuilder();
sb.Append($"{(!IsValid ? "Inv" : "V")}alid Elastic.Clients.Elasticsearch response built from a ");
sb.Append($"{(!IsValidResponse ? "Inv" : "V")}alid Elasticsearch response built from a ");
sb.AppendLine(ApiCallDetails?.ToString().ToCamelCase() ??
"null ApiCall which is highly exceptional, please open a bug if you see this");
if (!IsValid)
if (!IsValidResponse)
DebugIsValid(sb);

if (ApiCallDetails.ParsedHeaders is not null && ApiCallDetails.ParsedHeaders.TryGetValue("warning", out var warnings))
Expand All @@ -57,34 +56,34 @@ public string DebugInformation

if (ApiCallDetails != null)
Diagnostics.ResponseStatics.DebugInformationBuilder(ApiCallDetails, sb);

return sb.ToString();
}
}

/// <summary>
///
/// Shortcut to test if the response is considered to be successful.
/// </summary>
/// <returns></returns>
/// <returns>A <see cref="bool"/> indicating success or failure.</returns>
[JsonIgnore]
public virtual bool IsValid
public virtual bool IsValidResponse
{
get
{
var statusCode = ApiCallDetails?.HttpStatusCode;

// TODO - Review this on a request by reqeust basis
if (statusCode == 404)
return false;

return (ApiCallDetails?.Success ?? false) && (!ServerError?.HasError() ?? true);
return (ApiCallDetails?.HasSuccessfulStatusCode ?? false) && (!ElasticsearchServerError?.HasError() ?? true);
}
}

/// <summary>
///
/// </summary>
[JsonIgnore]
public ElasticsearchServerError ServerError { get; internal set; }
public ElasticsearchServerError ElasticsearchServerError { get; internal set; }

/// <summary>
///
Expand Down Expand Up @@ -112,5 +111,5 @@ protected virtual void DebugIsValid(StringBuilder sb) { }
/// </summary>
/// <returns></returns>
public override string ToString() =>
$"{(!IsValid ? "Inv" : "V")}alid Elastic.Clients.Elasticsearch response built from a {ApiCallDetails?.ToString().ToCamelCase()}";
$"{(!IsValidResponse ? "Inv" : "V")}alid Elastic.Clients.Elasticsearch response built from a {ApiCallDetails?.ToString().ToCamelCase()}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ protected override void SetErrorOnResponse<TResponse>(TResponse response, Elasti
{
if (response is ElasticsearchResponse elasticResponse)
{
elasticResponse.ServerError = error;
elasticResponse.ElasticsearchServerError = error;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Elastic.Transport/Products/ProductRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public abstract RequestData CreateSniffRequestData(Node node, IRequestConfigurat

/// <summary>
/// Used by <see cref="ResponseBuilder"/> to determine if it needs to return true or false for
/// <see cref="ApiCallDetails.Success"/>
/// <see cref="ApiCallDetails.HasSuccessfulStatusCode"/>
/// </summary>
public abstract bool HttpStatusCodeClassifier(HttpMethod method, int statusCode);

Expand Down
6 changes: 3 additions & 3 deletions src/Elastic.Transport/Responses/HttpDetails/ApiCallDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ public string DebugInformation
/// <summary>
///
/// </summary>
public bool Success { get; internal set; }
public bool HasSuccessfulStatusCode { get; internal set; }

/// <summary>
///
/// </summary>
internal bool SuccessOrKnownError =>
Success || HttpStatusCode >= 400
HasSuccessfulStatusCode || HttpStatusCode >= 400
&& HttpStatusCode < 599
&& HttpStatusCode != 504 //Gateway timeout needs to be retried
&& HttpStatusCode != 503 //service unavailable needs to be retried
Expand Down Expand Up @@ -134,5 +134,5 @@ public bool TryGetHeader(string key, out IEnumerable<string> headerValues) =>
/// A string summarising the API call.
/// </summary>
public override string ToString() =>
$"{(Success ? "S" : "Uns")}uccessful ({HttpStatusCode}) low level call on {HttpMethod.GetStringValue()}: {(Uri is not null ? Uri.PathAndQuery: "UNKNOWN URI")}";
$"{(HasSuccessfulStatusCode ? "S" : "Uns")}uccessful ({HttpStatusCode}) low level call on {HttpMethod.GetStringValue()}: {(Uri is not null ? Uri.PathAndQuery: "UNKNOWN URI")}";
}
29 changes: 3 additions & 26 deletions src/Elastic.Transport/Responses/ResponseFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,16 @@ namespace Elastic.Transport;
/// <summary>
/// TODO
/// </summary>
public static class ResponseFactory
public static class TestableResponseFactory
{
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateResponse<T>(T response, int statusCode) where T : TransportResponse =>
CreateResponse<T>(response, statusCode, true);

/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response"></param>
/// <param name="statusCode"></param>
/// <param name="success"></param>
/// <returns></returns>
public static T CreateResponse<T>(T response, int statusCode, bool success) where T : TransportResponse =>
CreateResponse<T>(response, statusCode, HttpMethod.GET, success);

/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="response"></param>
/// <param name="statusCode"></param>
/// <param name="httpMethod"></param>
/// <param name="success"></param>
/// <returns></returns>
public static T CreateResponse<T>(T response, int statusCode, HttpMethod httpMethod, bool success) where T : TransportResponse
public static T CreateResponse<T>(T response, int httpStatusCode) where T : TransportResponse
{
var apiCallDetails = new ApiCallDetails { HttpStatusCode = statusCode, Success = success, HttpMethod = httpMethod };
var apiCallDetails = new ApiCallDetails { HttpStatusCode = httpStatusCode };
return CreateResponse<T>(response, apiCallDetails);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public ControllerIntegrationTests(TransportTestServer instance) : base(instance)
public async Task CanCallIntoController()
{
var response = await Transport.GetAsync<StringResponse>("/dummy/20");
response.ApiCallDetails.Success.Should().BeTrue("{0}", response.ApiCallDetails.DebugInformation);
response.ApiCallDetails.HasSuccessfulStatusCode.Should().BeTrue("{0}", response.ApiCallDetails.DebugInformation);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public EndpointIntegrationTests(TransportTestServer<DummyStartup> instance) : ba
public async Task CanCallIntoEndpoint()
{
var response = await Transport.GetAsync<StringResponse>(DummyStartup.Endpoint);
response.ApiCallDetails.Success.Should().BeTrue("{0}", response.ApiCallDetails.DebugInformation);
response.ApiCallDetails.HasSuccessfulStatusCode.Should().BeTrue("{0}", response.ApiCallDetails.DebugInformation);
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/Elastic.Transport.Tests/VirtualClusterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ [Fact] public async Task ThrowsExceptionAfterDepleedingRules()

{ HealthyResponse, 9200, response =>
{
response.ApiCallDetails.Success.Should().BeTrue();
response.ApiCallDetails.HasSuccessfulStatusCode.Should().BeTrue();
response.ApiCallDetails.HttpStatusCode.Should().Be(200);
response.ApiCallDetails.DebugInformation.Should().Contain("x\":1");
} },
Expand Down Expand Up @@ -86,7 +86,7 @@ [Fact] public async Task RulesAreIgnoredAfterBeingExecuted()

{ HealthyResponse, 9200, response =>
{
response.ApiCallDetails.Success.Should().BeTrue();
response.ApiCallDetails.HasSuccessfulStatusCode.Should().BeTrue();
response.ApiCallDetails.HttpStatusCode.Should().Be(200);
response.ApiCallDetails.DebugInformation.Should().Contain("x\":1");
} },
Expand All @@ -95,7 +95,7 @@ [Fact] public async Task RulesAreIgnoredAfterBeingExecuted()

{ BadResponse, 9200, response =>
{
response.ApiCallDetails.Success.Should().BeFalse();
response.ApiCallDetails.HasSuccessfulStatusCode.Should().BeFalse();
response.ApiCallDetails.HttpStatusCode.Should().Be(500);
response.ApiCallDetails.DebugInformation.Should().Contain("x\":2");
} },
Expand Down

0 comments on commit 0f7b402

Please sign in to comment.