diff --git a/src/Elasticsearch.Net/Connection/InMemoryConnection.cs b/src/Elasticsearch.Net/Connection/InMemoryConnection.cs index a01fb5a96fc..b7995ad9db7 100644 --- a/src/Elasticsearch.Net/Connection/InMemoryConnection.cs +++ b/src/Elasticsearch.Net/Connection/InMemoryConnection.cs @@ -11,20 +11,22 @@ public class InMemoryConnection : IConnection { private readonly byte[] _responseBody; private readonly int _statusCode; + private readonly Exception _exception; public InMemoryConnection() { _statusCode = 200; } - public InMemoryConnection(byte[] responseBody, int statusCode = 200) + public InMemoryConnection(byte[] responseBody, int statusCode = 200, Exception exception = null) { _responseBody = responseBody; _statusCode = statusCode; + _exception = exception; } - public virtual Task> RequestAsync(RequestData requestData) where TReturn : class => - Task.FromResult(this.ReturnConnectionStatus(requestData)); + public virtual async Task> RequestAsync(RequestData requestData) where TReturn : class => + await this.ReturnConnectionStatusAsync(requestData).ConfigureAwait(false); public virtual ElasticsearchResponse Request(RequestData requestData) where TReturn : class => this.ReturnConnectionStatus(requestData); @@ -49,12 +51,40 @@ protected ElasticsearchResponse ReturnConnectionStatus(Request var builder = new ResponseBuilder(requestData) { StatusCode = statusCode ?? this._statusCode, - Stream = (body != null) ? new MemoryStream(body) : null + Stream = (body != null) ? new MemoryStream(body) : null, + Exception = _exception }; var cs = builder.ToResponse(); return cs; } + protected async Task> ReturnConnectionStatusAsync(RequestData requestData, byte[] responseBody = null, int? statusCode = null) + where TReturn : class + { + var body = responseBody ?? _responseBody; + var data = requestData.PostData; + if (data != null) + { + using (var stream = new MemoryStream()) + { + if (requestData.HttpCompression) + using (var zipStream = new GZipStream(stream, CompressionMode.Compress)) + await data.WriteAsync(zipStream, requestData.ConnectionSettings).ConfigureAwait(false); + else + await data.WriteAsync(stream, requestData.ConnectionSettings).ConfigureAwait(false); + } + } + + var builder = new ResponseBuilder(requestData) + { + StatusCode = statusCode ?? this._statusCode, + Stream = (body != null) ? new MemoryStream(body) : null, + Exception = _exception + }; + var cs = await builder.ToResponseAsync().ConfigureAwait(false); + return cs; + } + void IDisposable.Dispose() => DisposeManagedResources(); protected virtual void DisposeManagedResources() { } diff --git a/src/Elasticsearch.Net/Responses/ServerError.cs b/src/Elasticsearch.Net/Responses/ServerError.cs index f80034e6dec..f10ea14d814 100644 --- a/src/Elasticsearch.Net/Responses/ServerError.cs +++ b/src/Elasticsearch.Net/Responses/ServerError.cs @@ -14,7 +14,7 @@ public class ServerError public int Status { get; set; } public static ServerError Create(Stream stream) => ElasticsearchDefaultSerializer.Instance.Deserialize(stream); - public static Task CreateAsync(Stream stream, CancellationToken token) => + public static Task CreateAsync(Stream stream, CancellationToken token) => ElasticsearchDefaultSerializer.Instance.DeserializeAsync(stream, token); /// @@ -31,9 +31,9 @@ public static bool TryCreate(Stream stream, out ServerError serverError) /// /// Creating the server error might fail in cases where a proxy returns an http response which is not json at all /// - public static Task TryCreateAsync(Stream stream, CancellationToken token) + public static async Task TryCreateAsync(Stream stream, CancellationToken token) { - try { return CreateAsync(stream, token); } + try { return await CreateAsync(stream, token).ConfigureAwait(false); } catch { // ignored } return null; @@ -56,7 +56,7 @@ internal static ServerError Create(IDictionary dict, IJsonSerial }; } - public override string ToString() + public override string ToString() { var sb = new StringBuilder(); sb.Append($"ServerError: {Status}"); diff --git a/src/Profiling_Net45/Profiling.csproj b/src/Profiling_Net45/Profiling.csproj index 091093029d2..bb978d20260 100644 --- a/src/Profiling_Net45/Profiling.csproj +++ b/src/Profiling_Net45/Profiling.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU @@ -635,5 +634,6 @@ + \ No newline at end of file diff --git a/src/Tests/Framework/TestClient.cs b/src/Tests/Framework/TestClient.cs index 97da680ea0e..12ee4e58290 100644 --- a/src/Tests/Framework/TestClient.cs +++ b/src/Tests/Framework/TestClient.cs @@ -34,19 +34,19 @@ private static ConnectionSettings DefaultSettings(ConnectionSettings settings) = .Ignore(p => p.PrivateValue) .Rename(p => p.OnlineHandle, "nickname") ) - //We try and fetch the test name during integration tests when running fiddler to send the name + //We try and fetch the test name during integration tests when running fiddler to send the name //as the TestMethod header, this allows us to quickly identify which test sent which request .GlobalHeaders(new NameValueCollection { { "TestMethod", ExpensiveTestNameForIntegrationTests() } }); - + public static ConnectionSettings CreateSettings( - Func modifySettings = null, - int port = 9200, + Func modifySettings = null, + int port = 9200, bool forceInMemory = false, - Func createPool = null, + Func createPool = null, Func serializerFactory = null ) { @@ -77,16 +77,29 @@ public static IConnection CreateConnection(ConnectionSettings settings = null, b : new InMemoryConnection(); public static IElasticClient GetFixedReturnClient( - object responseJson, int statusCode = 200, Func modifySettings = null) + object response, + int statusCode = 200, + Func modifySettings = null, + string contentType = "application/json", + Exception exception = null) { var serializer = new JsonNetSerializer(new ConnectionSettings()); byte[] fixedResult; - using (var ms = new MemoryStream()) + + if (contentType == "application/json") { - serializer.Serialize(responseJson, ms); - fixedResult = ms.ToArray(); + using (var ms = new MemoryStream()) + { + serializer.Serialize(response, ms); + fixedResult = ms.ToArray(); + } } - var connection = new InMemoryConnection(fixedResult, statusCode); + else + { + fixedResult = Encoding.UTF8.GetBytes(response.ToString()); + } + + var connection = new InMemoryConnection(fixedResult, statusCode, exception); var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); var defaultSettings = new ConnectionSettings(connectionPool, connection); var settings = (modifySettings != null) ? modifySettings(defaultSettings) : defaultSettings; @@ -130,8 +143,8 @@ private static ITestConfiguration LoadConfiguration() // If running the classic .NET solution, tests run from bin/{config} directory, // but when running DNX solution, tests run from the test project root - var yamlConfigurationPath = directoryInfo.Name == "Tests" && - directoryInfo.Parent != null && + var yamlConfigurationPath = directoryInfo.Name == "Tests" && + directoryInfo.Parent != null && directoryInfo.Parent.Name == "src" ? "tests.yaml" : @"..\..\tests.yaml"; diff --git a/src/Tests/Reproduce/GithubIssue1901.cs b/src/Tests/Reproduce/GithubIssue1901.cs new file mode 100644 index 00000000000..65e5d116077 --- /dev/null +++ b/src/Tests/Reproduce/GithubIssue1901.cs @@ -0,0 +1,41 @@ +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Elasticsearch.Net; +using Nest; +using Tests.Framework; +using Tests.Framework.Integration; +using Xunit; +using FluentAssertions; + +namespace Tests.Reproduce +{ + public class GithubIssue1901 + { + private class Example + { + } + + private const string ProxyAuthResponse = @" +401 Authorization Required + +

401 Authorization Required

+
nginx/1.4.6 (Ubuntu)
+ + + + + + + +"; + + [U] + public async Task BadAuthResponseDoesNotThrowExceptionWhenAttemptingToDeserializeResponse() + { + var client = TestClient.GetFixedReturnClient(ProxyAuthResponse, 401, contentType: "text/html", exception: new Exception("problem with the request as a result of 401")); + var source = await client.LowLevel.GetSourceAsync("examples", "example", "1"); + source.Success.Should().BeFalse(); + } + } +} diff --git a/src/Tests/tests.yaml b/src/Tests/tests.yaml index 0ea63a0af78..74cf2393ae3 100644 --- a/src/Tests/tests.yaml +++ b/src/Tests/tests.yaml @@ -1,5 +1,5 @@ # mode either u (unit test), i (integration test) or m (mixed mode) -mode: u +mode: m # the elasticsearch version that should be started elasticsearch_version: 2.2.0 # whether we want to forcefully reseed on the node, if you are starting the tests with a node already running diff --git a/src/Tests_Net45/Tests.csproj b/src/Tests_Net45/Tests.csproj index 47a6293eba2..1a7901fa963 100644 --- a/src/Tests_Net45/Tests.csproj +++ b/src/Tests_Net45/Tests.csproj @@ -1,7 +1,6 @@  - Debug AnyCPU @@ -790,4 +789,5 @@ + \ No newline at end of file