Skip to content

Commit 7f100af

Browse files
committed
Merge branch 'fix/3378'
2 parents 0e662d8 + f898243 commit 7f100af

File tree

10 files changed

+232
-60
lines changed

10 files changed

+232
-60
lines changed

src/Elasticsearch.Net/Responses/ElasticsearchResponse.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,43 @@ namespace Elasticsearch.Net
88
/// </summary>
99
public abstract class ElasticsearchResponseBase : IApiCallDetails, IElasticsearchResponse
1010
{
11+
/// <inheritdoc />
1112
public IApiCallDetails ApiCall { get; set; }
12-
public List<Audit> AuditTrail => ApiCall.AuditTrail;
1313

14+
/// <inheritdoc cref="IApiCallDetails.DebugInformation"/>
1415
public string DebugInformation => ApiCall.DebugInformation;
15-
public IEnumerable<string> DeprecationWarnings => ApiCall.DeprecationWarnings;
16+
/// <inheritdoc cref="IApiCallDetails.HttpMethod"/>
1617
public HttpMethod HttpMethod => ApiCall.HttpMethod;
18+
/// <inheritdoc cref="IApiCallDetails.AuditTrail"/>
19+
public List<Audit> AuditTrail => ApiCall.AuditTrail;
20+
/// <inheritdoc cref="IApiCallDetails.DeprecationWarnings"/>
21+
public IEnumerable<string> DeprecationWarnings => ApiCall.DeprecationWarnings;
22+
/// <inheritdoc cref="IApiCallDetails.SuccessOrKnownError"/>
23+
public bool SuccessOrKnownError => ApiCall.SuccessOrKnownError;
24+
/// <inheritdoc cref="IApiCallDetails.HttpStatusCode"/>
1725
public int? HttpStatusCode => ApiCall.HttpStatusCode;
18-
public Exception OriginalException => ApiCall.OriginalException;
1926

20-
/// <summary>The raw byte request message body, only set when DisableDirectStreaming() is set on Connection configuration</summary>
21-
public byte[] RequestBodyInBytes => ApiCall.RequestBodyInBytes;
27+
/// <inheritdoc cref="IApiCallDetails.Success"/>
28+
public bool Success => ApiCall.Success;
29+
/// <inheritdoc cref="IApiCallDetails.OriginalException"/>
30+
public Exception OriginalException => ApiCall.OriginalException;
31+
/// <inheritdoc cref="IApiCallDetails.ResponseMimeType"/>
32+
public string ResponseMimeType => ApiCall.ResponseMimeType;
33+
/// <inheritdoc cref="IApiCallDetails.Uri"/>
34+
public Uri Uri => ApiCall.Uri;
2235

23-
/// <summary>The raw byte response message body, only set when DisableDirectStreaming() is set on Connection configuration</summary>
36+
/// <inheritdoc cref="IApiCallDetails.ResponseBodyInBytes"/>
2437
public byte[] ResponseBodyInBytes => ApiCall.ResponseBodyInBytes;
2538

26-
public string ResponseMimeType => ApiCall.ResponseMimeType;
39+
/// <inheritdoc cref="IApiCallDetails.RequestBodyInBytes"/>
40+
public byte[] RequestBodyInBytes => ApiCall.RequestBodyInBytes;
2741

28-
public bool Success => ApiCall.Success;
29-
public bool SuccessOrKnownError => ApiCall.SuccessOrKnownError;
30-
public Uri Uri => ApiCall.Uri;
42+
bool IElasticsearchResponse.TryGetServerErrorReason(out string reason) => TryGetServerErrorReason(out reason);
3143

44+
// TODO: Remove?
3245
//ignored
3346
List<Audit> IApiCallDetails.AuditTrail { get; set; }
3447

35-
bool IElasticsearchResponse.TryGetServerErrorReason(out string reason) => TryGetServerErrorReason(out reason);
36-
3748
protected virtual bool TryGetServerErrorReason(out string reason)
3849
{
3950
reason = null;
@@ -45,7 +56,7 @@ protected virtual bool TryGetServerErrorReason(out string reason)
4556

4657
/// <summary>
4758
/// A response from Elasticsearch including details about the request/response life cycle. Base class for the built in low level response
48-
/// types: <see cref="StringResponse" /> <see cref="BytesResponse" /> and <see cref="DynamicResponse" />
59+
/// types, <see cref="StringResponse"/>, <see cref="BytesResponse"/>, <see cref="DynamicResponse"/> and <see cref="VoidResponse"/>
4960
/// </summary>
5061
public abstract class ElasticsearchResponse<T> : ElasticsearchResponseBase
5162
{

src/Elasticsearch.Net/Responses/HttpDetails/IApiCallDetails.cs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@
44

55
namespace Elasticsearch.Net
66
{
7+
/// <summary>
8+
/// Details about the API call
9+
/// </summary>
710
public interface IApiCallDetails
811
{
9-
//TODO Get rid of setter
10-
/// <summary>
11-
/// An audit trail of requests made to nodes within the cluster
12-
/// </summary>
13-
List<Audit> AuditTrail { get; set; }
1412

15-
/// <summary>
16-
/// A lazy human readable string representation of what happened during this request for both successful and
17-
/// failed requests.
18-
/// </summary>
19-
string DebugInformation { get; }
13+
//TODO: Get rid of setter
14+
/// <summary>
15+
/// An audit trail of requests made to nodes within the cluster
16+
/// </summary>
17+
List<Audit> AuditTrail { get; set; }
18+
19+
/// <summary>
20+
/// A lazy human readable string representation of what happened during this request for both successful and
21+
/// failed requests.
22+
/// </summary>
23+
string DebugInformation { get; }
2024

2125
/// <summary>
2226
/// A collection of deprecation warnings returned from Elasticsearch.
@@ -35,28 +39,27 @@ public interface IApiCallDetails
3539
int? HttpStatusCode { get; }
3640

3741
/// <summary>
38-
/// If <see cref="Success" /> is <c>false</c>, this will hold the original exception.
39-
/// This will be the orginating CLR exception in most cases.
42+
/// If <see cref="Success"/> is <c>false</c>, this will hold the original exception.
43+
/// This will be the originating CLR exception in most cases.
4044
/// </summary>
4145
Exception OriginalException { get; }
4246

43-
/// <summary>
44-
/// The request body bytes.
45-
/// <para>NOTE: Only set when disable direct streaming is set for the request</para>
46-
/// </summary>
47-
[DebuggerDisplay("{RequestBodyInBytes != null ? System.Text.Encoding.UTF8.GetString(RequestBodyInBytes) : null,nq}")]
47+
/// <summary>
48+
/// The request body bytes.
49+
/// <para>NOTE: Only set when disable direct streaming is set for the request</para>
50+
/// </summary>
51+
[DebuggerDisplay("{RequestBodyInBytes != null ? System.Text.Encoding.UTF8.GetString(RequestBodyInBytes) : null,nq}")]
4852
byte[] RequestBodyInBytes { get; }
4953

50-
/// <summary>
51-
/// The response body bytes.
52-
/// <para>NOTE: Only set when disable direct streaming is set for the request</para>
53-
/// </summary>
54-
[DebuggerDisplay("{ResponseBodyInBytes != null ? System.Text.Encoding.UTF8.GetString(ResponseBodyInBytes) : null,nq}")]
54+
/// <summary>
55+
/// The response body bytes.
56+
/// <para>NOTE: Only set when disable direct streaming is set for the request</para>
57+
/// </summary>
58+
[DebuggerDisplay("{ResponseBodyInBytes != null ? System.Text.Encoding.UTF8.GetString(ResponseBodyInBytes) : null,nq}")]
5559
byte[] ResponseBodyInBytes { get; }
5660

57-
/// <summary>The response mime type </summary>
61+
/// <summary>The response MIME type </summary>
5862
string ResponseMimeType { get; }
59-
6063
/// <summary>
6164
/// The response status code is in the 200 range or is in the allowed list of status codes set on the request.
6265
/// </summary>

src/Elasticsearch.Net/Responses/ServerException/ServerError.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,24 @@ public ServerError(Error error, int? statusCode)
1818
public Error Error { get; }
1919
public int Status { get; }
2020

21+
public static bool TryCreate(Stream stream, out ServerError serverError)
22+
{
23+
try
24+
{
25+
serverError = Create(stream);
26+
return true;
27+
}
28+
catch
29+
{
30+
serverError = null;
31+
return false;
32+
}
33+
}
34+
2135
public static ServerError Create(Stream stream) =>
2236
LowLevelRequestResponseSerializer.Instance.Deserialize<ServerError>(stream);
2337

38+
// TODO: make token default parameter in 7.x
2439
public static Task<ServerError> CreateAsync(Stream stream, CancellationToken token) =>
2540
LowLevelRequestResponseSerializer.Instance.DeserializeAsync<ServerError>(stream, token);
2641

src/Elasticsearch.Net/Responses/Special/BytesResponse.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23

34
namespace Elasticsearch.Net
45
{
@@ -11,11 +12,11 @@ public BytesResponse() { }
1112
public bool TryGetServerError(out ServerError serverError)
1213
{
1314
serverError = null;
14-
if (Body == null || Body.Length == 0) return false;
15+
if (Body == null || Body.Length == 0 || ResponseMimeType != RequestData.MimeType)
16+
return false;
1517

16-
using (var stream = new MemoryStream(Body))
17-
serverError = ServerError.Create(stream);
18-
return true;
18+
using(var stream = new MemoryStream(Body))
19+
return ServerError.TryCreate(stream, out serverError);
1920
}
2021

2122
protected override bool TryGetServerErrorReason(out string reason)

src/Elasticsearch.Net/Responses/Special/StringResponse.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.IO;
1+
using System;
2+
using System.IO;
23
using System.Text;
34

45
namespace Elasticsearch.Net
@@ -12,11 +13,11 @@ public StringResponse() { }
1213
public bool TryGetServerError(out ServerError serverError)
1314
{
1415
serverError = null;
15-
if (string.IsNullOrEmpty(Body)) return false;
16+
if (string.IsNullOrEmpty(Body) || ResponseMimeType != RequestData.MimeType)
17+
return false;
1618

17-
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(Body)))
18-
serverError = ServerError.Create(stream);
19-
return true;
19+
using(var stream = new MemoryStream(Encoding.UTF8.GetBytes(Body)))
20+
return ServerError.TryCreate(stream, out serverError);
2021
}
2122

2223
protected override bool TryGetServerErrorReason(out string reason)

src/Tests/Tests.Core/Client/FixedResponseClient.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,25 @@ public static ConnectionSettings CreateConnectionSettings(
2828
)
2929
{
3030
var serializer = TestClient.Default.RequestResponseSerializer;
31-
byte[] fixedResult = null;
32-
if (response is string s) fixedResult = Encoding.UTF8.GetBytes(s);
33-
else if (contentType == RequestData.MimeType) fixedResult = serializer.SerializeToBytes(response);
34-
else fixedResult = Encoding.UTF8.GetBytes(response.ToString());
31+
byte[] responseBytes;
32+
switch (response)
33+
{
34+
case string s:
35+
responseBytes = Encoding.UTF8.GetBytes(s);
36+
break;
37+
case byte[] b:
38+
responseBytes = b;
39+
break;
40+
default:
41+
{
42+
responseBytes = contentType == RequestData.MimeType
43+
? serializer.SerializeToBytes(response)
44+
: Encoding.UTF8.GetBytes(response.ToString());
45+
break;
46+
}
47+
}
3548

36-
var connection = new InMemoryConnection(fixedResult, statusCode, exception, contentType);
49+
var connection = new InMemoryConnection(responseBytes, statusCode, exception, contentType);
3750
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
3851
var defaultSettings = new ConnectionSettings(connectionPool, connection)
3952
.DefaultIndex("default-index");

src/Tests/Tests/ClientConcepts/ConnectionPooling/Exceptions/UnrecoverableExceptions.doc.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Nest;
1010
using Tests.Domain;
1111
using Tests.Framework;
12+
using Tests.Framework.SerializationTests;
1213

1314
namespace Tests.ClientConcepts.ConnectionPooling.Exceptions
1415
{
@@ -99,14 +100,7 @@ [U] public async Task BadAuthenticationIsUnrecoverable()
99100
);
100101
}
101102

102-
private static byte[] HtmlNginx401Response = Encoding.UTF8.GetBytes(@"<html>
103-
<head><title>401 Authorization Required</title></head>
104-
<body bgcolor=""white"">
105-
<center><h1>401 Authorization Required</h1></center>
106-
<hr><center>nginx/1.4.6 (Ubuntu)</center>
107-
</body>
108-
</html>
109-
");
103+
private static byte[] HtmlNginx401Response = Encoding.UTF8.GetBytes(StubResponse.NginxHtml401Response);
110104

111105
/**
112106
* When a bad authentication response occurs, the client attempts to deserialize the response body returned;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Linq;
3+
using System.Text;
4+
using Elastic.Xunit.XunitPlumbing;
5+
using Elasticsearch.Net;
6+
using FluentAssertions;
7+
using Tests.Core.Client;
8+
using Tests.Core.ManagedElasticsearch.Clusters;
9+
10+
namespace Tests.Framework.SerializationTests
11+
{
12+
public class BytesResponseTests : IClusterFixture<ReadOnlyCluster>
13+
{
14+
private readonly ReadOnlyCluster _cluster;
15+
16+
public BytesResponseTests(ReadOnlyCluster cluster) => _cluster = cluster;
17+
18+
[I] public void NonNullBytesResponse()
19+
{
20+
var client = _cluster.Client;
21+
22+
var bytesResponse = client.LowLevel.Search<BytesResponse>("project", "project", PostData.Serializable(new { }));
23+
bytesResponse.Body.Should().NotBeNull();
24+
bytesResponse.Body.Should().BeEquivalentTo(bytesResponse.ResponseBodyInBytes);
25+
}
26+
27+
[I] public void NonNullBytesLowLevelResponse()
28+
{
29+
var settings = new ConnectionConfiguration(new Uri($"http://localhost:{_cluster.Nodes.First().Port ?? 9200}"));
30+
var lowLevelClient = new ElasticLowLevelClient(settings);
31+
32+
var bytesResponse = lowLevelClient.Search<BytesResponse>("project", "project", PostData.Serializable(new { }));
33+
34+
bytesResponse.Body.Should().NotBeNull();
35+
bytesResponse.Body.Should().BeEquivalentTo(bytesResponse.ResponseBodyInBytes);
36+
}
37+
38+
[U]
39+
public void TryGetServerErrorDoesNotThrowException()
40+
{
41+
var responseBytes = Encoding.UTF8.GetBytes(StubResponse.NginxHtml401Response);
42+
43+
var client = FixedResponseClient.Create(responseBytes, 401,
44+
modifySettings: s => s.DisableDirectStreaming(),
45+
contentType: "text/html",
46+
exception: new Exception("problem with the request as a result of 401")
47+
);
48+
49+
var bytesResponse = client.LowLevel.Search<BytesResponse>("project", "project", PostData.Serializable(new { }));
50+
51+
bytesResponse.Body.Should().NotBeNull();
52+
bytesResponse.Body.Should().BeEquivalentTo(responseBytes);
53+
bytesResponse.TryGetServerError(out var serverError).Should().BeFalse();
54+
serverError.Should().BeNull();
55+
}
56+
57+
[U] public void SkipDeserializationForStatusCodesSetsBody()
58+
{
59+
var responseBytes = Encoding.UTF8.GetBytes(StubResponse.NginxHtml401Response);
60+
61+
var client = FixedResponseClient.Create(responseBytes, 401,
62+
modifySettings: s => s.DisableDirectStreaming().SkipDeserializationForStatusCodes(401),
63+
contentType: "text/html",
64+
exception: new Exception("problem with the request as a result of 401")
65+
);
66+
67+
var bytesResponse = client.LowLevel.Search<BytesResponse>("project", "project", PostData.Serializable(new { }));
68+
69+
bytesResponse.Body.Should().NotBeNull();
70+
bytesResponse.Body.Should().BeEquivalentTo(responseBytes);
71+
}
72+
}
73+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Text;
3+
using Elastic.Xunit.XunitPlumbing;
4+
using Elasticsearch.Net;
5+
using FluentAssertions;
6+
using Tests.Core.Client;
7+
8+
namespace Tests.Framework.SerializationTests
9+
{
10+
public class StringResponseTests
11+
{
12+
[U] public void TryGetServerErrorDoesNotThrowException()
13+
{
14+
var client = FixedResponseClient.Create(StubResponse.NginxHtml401Response, 401,
15+
modifySettings: s => s.DisableDirectStreaming(),
16+
contentType: "text/html",
17+
exception: new Exception("problem with the request as a result of 401")
18+
);
19+
20+
var stringResponse = client.LowLevel.Search<StringResponse>("project", "project", PostData.Serializable(new { }));
21+
22+
stringResponse.Body.Should().NotBeNull();
23+
stringResponse.Body.Should().Be(StubResponse.NginxHtml401Response);
24+
stringResponse.TryGetServerError(out var serverError).Should().BeFalse();
25+
serverError.Should().BeNull();
26+
}
27+
28+
[U] public void SkipDeserializationForStatusCodesSetsBody()
29+
{
30+
var client = FixedResponseClient.Create(StubResponse.NginxHtml401Response, 401,
31+
modifySettings: s => s.DisableDirectStreaming().SkipDeserializationForStatusCodes(401),
32+
contentType: "text/html",
33+
exception: new Exception("problem with the request as a result of 401")
34+
);
35+
36+
var stringResponse = client.LowLevel.Search<StringResponse>("project", "project", PostData.Serializable(new { }));
37+
38+
stringResponse.Body.Should().NotBeNull();
39+
stringResponse.Body.Should().Be(StubResponse.NginxHtml401Response);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)