Skip to content

Commit

Permalink
Refactor generation of exceptions from code strings (#757)
Browse files Browse the repository at this point in the history
* Add new exception types and change to explicitly idetifying fast fail errors

* Add some missing fail fast types

* Added unknown security exceptions

* Fix TokenExpiredException reporting to testkit

* Address review notes

* Refactor client error handling

* Renaming things

* Add code for ClientException, correct attribute inheritance and move it to internal.

* Update for IsRetriable changes

* Review notes

* Move classes into files

* fix ExecuteQuery testkit dto

* refactor exception creation

* Add txMeta to ExecuteQueryConfigDto
  • Loading branch information
RichardIrons-neo4j committed Dec 13, 2023
1 parent 6c91e8e commit da06979
Show file tree
Hide file tree
Showing 35 changed files with 1,398 additions and 703 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ internal static class ExceptionManager
{ typeof(NotSupportedException), "NotSupportedException" },
{ typeof(ArgumentException), "ArgumentError" },
{ typeof(InvalidBookmarkMixtureException), "InvalidBookmarkMixtureError" },
{ typeof(ArgumentErrorException), "ArgumentError" },
{ typeof(StatementArgumentException), "ArgumentError" },
{ typeof(TypeException), "TypeError" },
{ typeof(ForbiddenException), "ForbiddenError" },
{ typeof(UnknownSecurityException), "OtherSecurityException" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Neo4j.Driver.Internal.Auth;
using Newtonsoft.Json;

namespace Neo4j.Driver.Tests.TestBackend;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using FluentAssertions;
using Neo4j.Driver.Internal.ExceptionHandling;
using Xunit;

namespace Neo4j.Driver.Tests.Exceptions;

public class Neo4jExceptionFactoryTests
{
public static IEnumerable<object[]> CodeToTypeMapping = new[]
{
new object[] { "Neo.ClientError.Statement.ArgumentError", typeof(StatementArgumentException) },
new object[] { "Neo.ClientError.Security.Unauthorized", typeof(AuthenticationException) },
new object[] { "Neo.ClientError.Security.AuthorizationExpired", typeof(AuthorizationException) },
new object[] { "Neo.ClientError.Database.DatabaseNotFound", typeof(FatalDiscoveryException) },
new object[] { "Neo.ClientError.Security.Forbidden", typeof(ForbiddenException) },
new object[] { "Neo.ClientError.Transaction.InvalidBookmark", typeof(InvalidBookmarkException) },
new object[] { "Neo.ClientError.Transaction.InvalidBookmarkMixture", typeof(InvalidBookmarkMixtureException) },
new object[] { "Neo.ClientError.Request.Invalid", typeof(ProtocolException) },
new object[] { "Neo.ClientError.Request.InvalidFormat", typeof(ProtocolException) },
new object[] { "Neo.ClientError.Security.TokenExpired", typeof(TokenExpiredException) },
new object[] { "Neo.ClientError.Statement.TypeError", typeof(TypeException) },
new object[] { "Neo.ClientError.Security.##unknown##", typeof(UnknownSecurityException) },
new object[] { "Neo.DatabaseError.blah", typeof(DatabaseException) },
new object[] { "Neo.TransientError.TemporaryDisabled", typeof(TransientException) },
};

[Theory, MemberData(nameof(CodeToTypeMapping))]
public void ShouldCreateCorrectExceptionType(string code, Type exceptionType)
{
var subject = new Neo4jExceptionFactory();
var exception = subject.GetException(code, "test message");
exception.Should().BeOfType(exceptionType);
exception.Code.Should().Be(code);
exception.Message.Should().Be("test message");
}
}
38 changes: 38 additions & 0 deletions Neo4j.Driver/Neo4j.Driver/Exceptions/AuthenticationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Runtime.Serialization;
using Neo4j.Driver.Internal.ExceptionHandling;

namespace Neo4j.Driver;

/// <summary>
/// Failed to authenticate the client to the server due to bad credentials
/// To recover from this error, close the current driver and restart with the correct credentials
/// </summary>
[DataContract]
[ErrorCode("Neo.ClientError.Security.Unauthorized")]
public class AuthenticationException : SecurityException
{
/// <summary>
/// Create a new <see cref="AuthenticationException"/> with an error message.
/// </summary>
/// <param name="message">The error message.</param>
public AuthenticationException(string message) : base(message)
{
}
}
37 changes: 37 additions & 0 deletions Neo4j.Driver/Neo4j.Driver/Exceptions/AuthorizationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Neo4j.Driver.Internal.ExceptionHandling;

namespace Neo4j.Driver;

/// <summary>
/// The authorization information maintained on the server has expired. The client should reconnect.
/// </summary>
[ErrorCode("Neo.ClientError.Security.AuthorizationExpired")]
public class AuthorizationException : SecurityException
{
public override bool IsRetriable => true;

/// <summary>
/// Create a new <see cref="AuthorizationException"/> with an error message.
/// </summary>
/// <param name="message">The error message.</param>
public AuthorizationException(string message) : base(message)
{
}
}
76 changes: 76 additions & 0 deletions Neo4j.Driver/Neo4j.Driver/Exceptions/ClientException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Runtime.Serialization;
using Neo4j.Driver.Internal.ExceptionHandling;

namespace Neo4j.Driver;

/// <summary>
/// A <see cref="ClientException"/> indicates that the client has carried out an operation incorrectly.
/// The error code provided can be used to determine further detail for the problem.
/// </summary>
[DataContract]
[ErrorCode("Neo.ClientError.*")]
public class ClientException : Neo4jException
{
/// <summary>
/// Create a new <see cref="ClientException"/>.
/// </summary>
public ClientException()
{
}

/// <summary>
/// Create a new <see cref="ClientException"/> with an error message.
/// </summary>
/// <param name="message">The error message.</param>
public ClientException(string message) : base(message)
{
}

/// <summary>
/// Create a new <see cref="ClientException"/> with an error code and an error message.
/// </summary>
/// <param name="code">The error code.</param>
/// <param name="message">The error message.</param>
public ClientException(string code, string message) : base(code, message)
{
}

/// <summary>
/// Create a new <see cref="ClientException"/> with an error message and an exception.
/// </summary>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception.</param>
public ClientException(string message, Exception innerException)
: base(message, innerException)
{
}

/// <summary>
/// Create a new <see cref="ClientException"/> with an error code, an error message and an exception.
/// </summary>
/// <param name="code">The error code.</param>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception.</param>
public ClientException(string code, string message, Exception innerException)
: base(code, message, innerException)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Runtime.Serialization;

namespace Neo4j.Driver;

/// <summary>
/// A <see cref="ConnectionReadTimeoutException"/> indicates that the driver timed out trying to read from the network socket.
/// </summary>
[DataContract]
public class ConnectionReadTimeoutException : Neo4jException
{
public override bool IsRetriable => true;

/// <summary>
/// Create a new <see cref="ConnectionReadTimeoutException"/> with an error message.
/// </summary>
/// <param name="message">The error message.</param>
public ConnectionReadTimeoutException(string message) : base(message)
{
}

/// <summary>
/// Create a new <see cref="ConnectionReadTimeoutException"/> with an error message and an exception.
/// </summary>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception.</param>
public ConnectionReadTimeoutException(string message, Exception innerException) : base(message, innerException)
{
}
}
66 changes: 66 additions & 0 deletions Neo4j.Driver/Neo4j.Driver/Exceptions/DatabaseException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Runtime.Serialization;
using Neo4j.Driver.Internal.ExceptionHandling;

namespace Neo4j.Driver;

/// <summary>
/// A <see cref="DatabaseException"/> indicates that there is a problem within the underlying database.
/// The error code provided can be used to determine further detail for the problem.
/// </summary>
[DataContract]
[ErrorCode("*")] // mop up any errors that haven't already been handled
public class DatabaseException : Neo4jException
{
/// <summary>
/// Create a new <see cref="DatabaseException"/>.
/// </summary>
public DatabaseException()
{
}

/// <summary>
/// Create a new <see cref="DatabaseException"/> with an error error message.
/// </summary>
/// <param name="message">The error message.</param>
public DatabaseException(string message) : base(string.Empty, message)
{
}

/// <summary>
/// Create a new <see cref="DatabaseException"/> with an error code and an error message.
/// </summary>
/// <param name="code">The error code.</param>
/// <param name="message">The error message.</param>
public DatabaseException(string code, string message) : base(code, message)
{
}

/// <summary>
/// Create a new <see cref="DatabaseException"/> with an error code, an error message and an exception.
/// </summary>
/// <param name="code">The error code.</param>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception which caused this error.</param>
public DatabaseException(string code, string message, Exception innerException)
: base(code, message, innerException)
{
}
}
39 changes: 39 additions & 0 deletions Neo4j.Driver/Neo4j.Driver/Exceptions/FatalDiscoveryException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) "Neo4j"
// Neo4j Sweden AB [http://neo4j.com]
//
// This file is part of Neo4j.
//
// Licensed under the Apache License, Version 2.0 (the "License"):
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Runtime.Serialization;
using Neo4j.Driver.Internal.ExceptionHandling;

namespace Neo4j.Driver;

/// <summary>
/// There was an error that points us to a fatal problem for routing table discovery, like the requested database
/// could not be found. This kind of errors are identified as non-transient and are not retried.
/// </summary>
[DataContract]
[ErrorCode("Neo.ClientError.Database.DatabaseNotFound")]
public class FatalDiscoveryException : ClientException
{
/// <summary>
/// Create a new <see cref="FatalDiscoveryException"/> with an error code and an error message.
/// </summary>
/// <param name="message">The error message.</param>
public FatalDiscoveryException(string message)
: base(message)
{
}
}
Loading

0 comments on commit da06979

Please sign in to comment.