Commit fa8a5b57 authored by DeepakVerma's avatar DeepakVerma

SE.Redis surface error information

parent 23beb2f6
using System; using NUnit.Framework;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using NUnit.Framework;
using System.Threading; using System.Threading;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
...@@ -30,21 +24,15 @@ public void SSLCertificateValidationError(bool isCertValidationSucceeded) ...@@ -30,21 +24,15 @@ public void SSLCertificateValidationError(bool isCertValidationSucceeded)
{ {
connection.ConnectionFailed += (object sender, ConnectionFailedEventArgs e) => connection.ConnectionFailed += (object sender, ConnectionFailedEventArgs e) =>
{ {
Assert.That(e.FailureType.ToString(), Is.EqualTo(ConnectionFailureType.AuthenticationFailure.ToString())); Assert.That(e.FailureType, Is.EqualTo(ConnectionFailureType.AuthenticationFailure));
}; };
if (!isCertValidationSucceeded) if (!isCertValidationSucceeded)
{ {
//validate that in this case it throws an certificatevalidation exception //validate that in this case it throws an certificatevalidation exception
var ex = Assert.Throws<RedisConnectionException>(() => connection.GetDatabase().Ping()); var ex = Assert.Throws<RedisConnectionException>(() => connection.GetDatabase().Ping());
var rde = (RedisConnectionException)ex.InnerException;
((AggregateException)ex.InnerException).Handle(e => Assert.That(rde.FailureType, Is.EqualTo(ConnectionFailureType.AuthenticationFailure));
{ Assert.That(rde.InnerException.Message, Is.EqualTo("The remote certificate is invalid according to the validation procedure."));
var rde = (RedisConnectionException)e;
Assert.That(rde.FailureType.ToString(), Is.EqualTo(ConnectionFailureType.AuthenticationFailure.ToString()));
Assert.That(rde.InnerException.Message, Is.EqualTo("The remote certificate is invalid according to the validation procedure."));
return e is RedisConnectionException;
});
} }
else else
{ {
...@@ -72,17 +60,12 @@ public void AuthenticationFailureError() ...@@ -72,17 +60,12 @@ public void AuthenticationFailureError()
{ {
muxer.ConnectionFailed += (object sender, ConnectionFailedEventArgs e) => muxer.ConnectionFailed += (object sender, ConnectionFailedEventArgs e) =>
{ {
Assert.That(e.FailureType.ToString(), Is.EqualTo(ConnectionFailureType.AuthenticationFailure.ToString())); Assert.That(e.FailureType, Is.EqualTo(ConnectionFailureType.AuthenticationFailure));
}; };
var ex = Assert.Throws<RedisConnectionException>(() => muxer.GetDatabase().Ping()); var ex = Assert.Throws<RedisConnectionException>(() => muxer.GetDatabase().Ping());
var rde = (RedisConnectionException)ex.InnerException;
((AggregateException)ex.InnerException).Handle(e => Assert.That(rde.FailureType, Is.EqualTo(ConnectionFailureType.AuthenticationFailure));
{ Assert.That(rde.InnerException.Message, Is.EqualTo("Error: NOAUTH Authentication required. Verify if the Redis password provided is correct."));
var rde = (RedisConnectionException)e;
Assert.That(rde.FailureType.ToString(), Is.EqualTo(ConnectionFailureType.AuthenticationFailure.ToString()));
return e is RedisConnectionException;
});
//wait for a second for connectionfailed event to fire //wait for a second for connectionfailed event to fire
Thread.Sleep(1000); Thread.Sleep(1000);
} }
...@@ -99,12 +82,8 @@ public void SocketFailureError() ...@@ -99,12 +82,8 @@ public void SocketFailureError()
using (var muxer = ConnectionMultiplexer.Connect(options)) using (var muxer = ConnectionMultiplexer.Connect(options))
{ {
var ex = Assert.Throws<RedisConnectionException>(() => muxer.GetDatabase().Ping()); var ex = Assert.Throws<RedisConnectionException>(() => muxer.GetDatabase().Ping());
((AggregateException)ex.InnerException).Handle(e => var rde = (RedisConnectionException)ex.InnerException;
{ Assert.That(rde.FailureType, Is.EqualTo(ConnectionFailureType.SocketFailure));
var rde = (RedisConnectionException)e;
Assert.That(rde.FailureType.ToString(), Is.EqualTo(ConnectionFailureType.SocketFailure.ToString()));
return e is RedisConnectionException;
});
} }
} }
...@@ -123,13 +102,13 @@ public void CheckFailureRecovered() ...@@ -123,13 +102,13 @@ public void CheckFailureRecovered()
server.SimulateConnectionFailure(); server.SimulateConnectionFailure();
Assert.AreEqual(ConnectionFailureType.SocketFailure, ((RedisConnectionException)muxer.GetServerSnapShot()[0].LastException).FailureType); Assert.AreEqual(ConnectionFailureType.SocketFailure, ((RedisConnectionException)muxer.GetServerSnapshot()[0].LastException).FailureType);
// should reconnect within 1 keepalive interval // should reconnect within 1 keepalive interval
muxer.AllowConnect = true; muxer.AllowConnect = true;
Thread.Sleep(2000); Thread.Sleep(2000);
Assert.Null(muxer.GetServerSnapShot()[0].LastException); Assert.Null(muxer.GetServerSnapshot()[0].LastException);
} }
} }
finally finally
......
using System;
using NUnit.Framework;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class ExceptionFactoryTests : TestBase
{
[Test]
public void NullLastException()
{
using (var muxer = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true))
{
var conn = muxer.GetDatabase();
Assert.Null(muxer.GetServerSnapshot()[0].LastException);
var ex = ExceptionFactory.NoConnectionAvailable(true, new RedisCommand(), null, null, muxer.GetServerSnapshot());
Assert.Null(ex.InnerException);
}
}
[Test]
public void NullSnapshot()
{
var ex = ExceptionFactory.NoConnectionAvailable(true, new RedisCommand(), null, null, null);
Assert.Null(ex.InnerException);
}
[Test]
public void MultipleEndpointsThrowAggregateException()
{
try
{
using (var muxer = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true))
{
var conn = muxer.GetDatabase();
muxer.AllowConnect = false;
SocketManager.ConnectCompletionType = CompletionType.Async;
foreach (var endpoint in muxer.GetEndPoints())
{
muxer.GetServer(endpoint).SimulateConnectionFailure();
}
var ex = ExceptionFactory.NoConnectionAvailable(true, new RedisCommand(), null, null, muxer.GetServerSnapshot());
Assert.IsInstanceOf<RedisConnectionException>(ex);
Assert.IsInstanceOf<AggregateException>(ex.InnerException);
var aggException = (AggregateException)ex.InnerException;
Assert.That(aggException.InnerExceptions.Count, Is.EqualTo(2));
for (int i = 0; i < aggException.InnerExceptions.Count; i++)
{
Assert.That(((RedisConnectionException)aggException.InnerExceptions[i]).FailureType, Is.EqualTo(ConnectionFailureType.SocketFailure));
}
}
}
finally
{
SocketManager.ConnectCompletionType = CompletionType.Any;
ClearAmbientFailures();
}
}
[Test]
public void NullInnerExceptionForMultipleEndpointsWithNoLastException()
{
try
{
using (var muxer = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true))
{
var conn = muxer.GetDatabase();
muxer.AllowConnect = false;
SocketManager.ConnectCompletionType = CompletionType.Async;
var ex = ExceptionFactory.NoConnectionAvailable(true, new RedisCommand(), null, null, muxer.GetServerSnapshot());
Assert.IsInstanceOf<RedisConnectionException>(ex);
Assert.Null(ex.InnerException);
}
}
finally
{
SocketManager.ConnectCompletionType = CompletionType.Any;
ClearAmbientFailures();
}
}
[Test]
public void ServerTakesPrecendenceOverSnapshot()
{
try
{
using (var muxer = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true))
{
var conn = muxer.GetDatabase();
muxer.AllowConnect = false;
SocketManager.ConnectCompletionType = CompletionType.Async;
muxer.GetServer(muxer.GetEndPoints()[0]).SimulateConnectionFailure();
var ex = ExceptionFactory.NoConnectionAvailable(true, new RedisCommand(), null,muxer.GetServerSnapshot()[0], muxer.GetServerSnapshot());
Assert.IsInstanceOf<RedisConnectionException>(ex);
Assert.IsInstanceOf<Exception>(ex.InnerException);
Assert.That(muxer.GetServerSnapshot()[0].LastException, Is.EqualTo(ex.InnerException));
}
}
finally
{
SocketManager.ConnectCompletionType = CompletionType.Any;
ClearAmbientFailures();
}
}
}
}
...@@ -18,7 +18,7 @@ public enum ConnectionFailureType ...@@ -18,7 +18,7 @@ public enum ConnectionFailureType
/// </summary> /// </summary>
SocketFailure, SocketFailure,
/// <summary> /// <summary>
/// The connection did not authenticate correctly /// Either SSL Stream or Redis authentication failed
/// </summary> /// </summary>
AuthenticationFailure, AuthenticationFailure,
/// <summary> /// <summary>
......
...@@ -295,7 +295,7 @@ internal void MakeMaster(ServerEndPoint server, ReplicationChangeOptions options ...@@ -295,7 +295,7 @@ internal void MakeMaster(ServerEndPoint server, ReplicationChangeOptions options
if (server == null) throw new ArgumentNullException(nameof(server)); if (server == null) throw new ArgumentNullException(nameof(server));
var srv = new RedisServer(this, server, null); var srv = new RedisServer(this, server, null);
if (!srv.IsConnected) throw ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, RedisCommand.SLAVEOF, null, server, GetServerSnapShot()); if (!srv.IsConnected) throw ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, RedisCommand.SLAVEOF, null, server, GetServerSnapshot());
if (log == null) log = TextWriter.Null; if (log == null) log = TextWriter.Null;
CommandMap.AssertAvailable(RedisCommand.SLAVEOF); CommandMap.AssertAvailable(RedisCommand.SLAVEOF);
...@@ -1657,7 +1657,7 @@ internal void UpdateClusterRange(ClusterConfiguration configuration) ...@@ -1657,7 +1657,7 @@ internal void UpdateClusterRange(ClusterConfiguration configuration)
private readonly ServerSelectionStrategy serverSelectionStrategy; private readonly ServerSelectionStrategy serverSelectionStrategy;
internal ServerEndPoint[] GetServerSnapShot() internal ServerEndPoint[] GetServerSnapshot()
{ {
var tmp = serverSnapshot; var tmp = serverSnapshot;
return tmp; return tmp;
...@@ -1872,7 +1872,7 @@ internal Task<T> ExecuteAsyncImpl<T>(Message message, ResultProcessor<T> process ...@@ -1872,7 +1872,7 @@ internal Task<T> ExecuteAsyncImpl<T>(Message message, ResultProcessor<T> process
var source = ResultBox<T>.Get(tcs); var source = ResultBox<T>.Get(tcs);
if (!TryPushMessageToBridge(message, processor, source, ref server)) if (!TryPushMessageToBridge(message, processor, source, ref server))
{ {
ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server, GetServerSnapShot())); ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server, GetServerSnapshot()));
} }
return tcs.Task; return tcs.Task;
} }
...@@ -1913,7 +1913,7 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1913,7 +1913,7 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
{ {
if (!TryPushMessageToBridge(message, processor, source, ref server)) if (!TryPushMessageToBridge(message, processor, source, ref server))
{ {
throw ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server, GetServerSnapShot()); throw ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server, GetServerSnapshot());
} }
if (Monitor.Wait(source, timeoutMilliseconds)) if (Monitor.Wait(source, timeoutMilliseconds))
......
...@@ -85,9 +85,8 @@ internal static Exception NoConnectionAvailable(bool includeDetail, RedisCommand ...@@ -85,9 +85,8 @@ internal static Exception NoConnectionAvailable(bool includeDetail, RedisCommand
//otherwise it would output state of all the endpoints //otherwise it would output state of all the endpoints
serverSnapshot = new ServerEndPoint[] { server }; serverSnapshot = new ServerEndPoint[] { server };
} }
List<Exception> data; string exceptionmessage = "No connection is available to service this operation: " + s ;
string exceptionmessage = "No connection is available to service this operation: " + s + GetServerSnapShotLabel(serverSnapshot, out data); var ex = new RedisConnectionException(ConnectionFailureType.UnableToResolvePhysicalConnection, exceptionmessage, GetServerSnapshotInnerExceptions(serverSnapshot));
var ex = new RedisConnectionException(ConnectionFailureType.UnableToResolvePhysicalConnection, exceptionmessage,new AggregateException(data));
if (includeDetail) if (includeDetail)
{ {
AddDetail(ex, message, server, s); AddDetail(ex, message, server, s);
...@@ -95,37 +94,29 @@ internal static Exception NoConnectionAvailable(bool includeDetail, RedisCommand ...@@ -95,37 +94,29 @@ internal static Exception NoConnectionAvailable(bool includeDetail, RedisCommand
return ex; return ex;
} }
internal static string GetServerSnapShotLabel(ServerEndPoint[] serverSnapshot, out List<Exception> data) internal static Exception GetServerSnapshotInnerExceptions(ServerEndPoint[] serverSnapshot)
{ {
List<Exception> exceptions = new List<Exception>(); List<Exception> innerExceptions = new List<Exception>();
StringBuilder connectionStateSummary = new StringBuilder();
Action<string, string> add = (k, v) =>
{
connectionStateSummary.Append("; ");
connectionStateSummary.Append(k);
connectionStateSummary.Append(":");
connectionStateSummary.Append(v);
};
if (serverSnapshot != null) if (serverSnapshot != null)
{ {
string serverSnapshotName;
for (int i = 0; i < serverSnapshot.Length; i++) for (int i = 0; i < serverSnapshot.Length; i++)
{ {
serverSnapshotName = serverSnapshot[i].EndPoint.ToString(); if (serverSnapshot[i].LastException != null)
add(DataServerEndpoint, serverSnapshot[i].EndPoint.ToString());
add(DataConnectionState, serverSnapshot[i].ConnectionState.ToString());
if (serverSnapshot[i].LastException != null && serverSnapshot[i].LastException is RedisConnectionException)
{ {
var lastException = ((RedisConnectionException)serverSnapshot[i].LastException); var lastException = serverSnapshot[i].LastException;
exceptions.Add(lastException); innerExceptions.Add(lastException);
add(DataLastFailure, lastException.FailureType.ToString());
add(DataLastInnerException, lastException.InnerException?.Message);
} }
} }
} }
data = exceptions; if (innerExceptions.Count == 1)
return connectionStateSummary.ToString(); {
return innerExceptions[0];
}
else if(innerExceptions.Count > 1)
{
return new AggregateException(innerExceptions);
}
return null;
} }
internal static Exception NotSupported(bool includeDetail, RedisCommand command) internal static Exception NotSupported(bool includeDetail, RedisCommand command)
...@@ -158,7 +149,6 @@ private static void AddDetail(Exception exception, Message message, ServerEndPoi ...@@ -158,7 +149,6 @@ private static void AddDetail(Exception exception, Message message, ServerEndPoi
if (server != null) exception.Data.Add(DataServerKey, Format.ToString(server.EndPoint)); if (server != null) exception.Data.Add(DataServerKey, Format.ToString(server.EndPoint));
} }
} }
static string GetLabel(bool includeDetail, RedisCommand command, Message message) static string GetLabel(bool includeDetail, RedisCommand command, Message message)
......
...@@ -70,7 +70,6 @@ public enum State : byte ...@@ -70,7 +70,6 @@ public enum State : byte
public ConnectionType ConnectionType { get; } public ConnectionType ConnectionType { get; }
public bool IsConnected => state == (int)State.ConnectedEstablished; public bool IsConnected => state == (int)State.ConnectedEstablished;
public ConnectionMultiplexer Multiplexer { get; } public ConnectionMultiplexer Multiplexer { get; }
...@@ -267,7 +266,7 @@ internal void KeepAlive() ...@@ -267,7 +266,7 @@ internal void KeepAlive()
Multiplexer.Trace("Enqueue: " + msg); Multiplexer.Trace("Enqueue: " + msg);
if (!TryEnqueue(msg, ServerEndPoint.IsSlave)) if (!TryEnqueue(msg, ServerEndPoint.IsSlave))
{ {
OnInternalError(ExceptionFactory.NoConnectionAvailable(Multiplexer.IncludeDetailInExceptions, msg.Command, msg, ServerEndPoint, Multiplexer.GetServerSnapShot())); OnInternalError(ExceptionFactory.NoConnectionAvailable(Multiplexer.IncludeDetailInExceptions, msg.Command, msg, ServerEndPoint, Multiplexer.GetServerSnapshot()));
} }
} }
} }
......
...@@ -30,13 +30,13 @@ public void Execute() ...@@ -30,13 +30,13 @@ public void Execute()
if (server == null) if (server == null)
{ {
FailNoServer(snapshot); FailNoServer(snapshot);
throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server,multiplexer.GetServerSnapShot()); throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server,multiplexer.GetServerSnapshot());
} }
var bridge = server.GetBridge(message.Command); var bridge = server.GetBridge(message.Command);
if (bridge == null) if (bridge == null)
{ {
FailNoServer(snapshot); FailNoServer(snapshot);
throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapShot()); throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapshot());
} }
// identity a list // identity a list
......
...@@ -542,7 +542,7 @@ internal override Task<T> ExecuteAsync<T>(Message message, ResultProcessor<T> pr ...@@ -542,7 +542,7 @@ internal override Task<T> ExecuteAsync<T>(Message message, ResultProcessor<T> pr
// no need to deny exec-sync here; will be complete before they see if // no need to deny exec-sync here; will be complete before they see if
var tcs = TaskSource.Create<T>(asyncState); var tcs = TaskSource.Create<T>(asyncState);
ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapShot())); ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapshot()));
return tcs.Task; return tcs.Task;
} }
return base.ExecuteAsync<T>(message, processor, server); return base.ExecuteAsync<T>(message, processor, server);
...@@ -555,7 +555,7 @@ internal override T ExecuteSync<T>(Message message, ResultProcessor<T> processor ...@@ -555,7 +555,7 @@ internal override T ExecuteSync<T>(Message message, ResultProcessor<T> processor
if (!server.IsConnected) if (!server.IsConnected)
{ {
if (message == null || message.IsFireAndForget) return default(T); if (message == null || message.IsFireAndForget) return default(T);
throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapShot()); throw ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, server, multiplexer.GetServerSnapshot());
} }
return base.ExecuteSync<T>(message, processor, server); return base.ExecuteSync<T>(message, processor, server);
} }
......
...@@ -1165,7 +1165,7 @@ public override bool SetResult(PhysicalConnection connection, Message message, R ...@@ -1165,7 +1165,7 @@ public override bool SetResult(PhysicalConnection connection, Message message, R
{ {
if (result.IsEqual(authFail) || result.IsEqual(authRequired)) if (result.IsEqual(authFail) || result.IsEqual(authRequired))
{ {
connection.RecordConnectionFailed(ConnectionFailureType.AuthenticationFailure); connection.RecordConnectionFailed(ConnectionFailureType.AuthenticationFailure, new Exception(result.ToString() + " Verify if the Redis password provided is correct."));
} }
else if (result.AssertStarts(loading)) else if (result.AssertStarts(loading))
{ {
......
...@@ -119,9 +119,6 @@ internal PhysicalBridge.State ConnectionState ...@@ -119,9 +119,6 @@ internal PhysicalBridge.State ConnectionState
} }
} }
public bool IsSlave { get { return isSlave; } set { SetConfig(ref isSlave, value); } } public bool IsSlave { get { return isSlave; } set { SetConfig(ref isSlave, value); } }
public long OperationCount public long OperationCount
...@@ -555,7 +552,7 @@ internal Task<T> QueueDirectAsync<T>(Message message, ResultProcessor<T> process ...@@ -555,7 +552,7 @@ internal Task<T> QueueDirectAsync<T>(Message message, ResultProcessor<T> process
if (bridge == null) bridge = GetBridge(message.Command); if (bridge == null) bridge = GetBridge(message.Command);
if (!bridge.TryEnqueue(message, isSlave)) if (!bridge.TryEnqueue(message, isSlave))
{ {
ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, this, multiplexer.GetServerSnapShot())); ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, this, multiplexer.GetServerSnapshot()));
} }
return tcs.Task; return tcs.Task;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment