Skip to content

Commit

Permalink
investigate #2077
Browse files Browse the repository at this point in the history
  • Loading branch information
mgravell committed Apr 26, 2024
1 parent d9fed73 commit cc3d542
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 2 deletions.
124 changes: 124 additions & 0 deletions tests/Dapper.Tests/ErrorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Data;
using System.Data.Common;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Dapper.Tests;

[Collection("ErrorTests")]
public sealed class SystemSqlClientErrorTests(ITestOutputHelper Log) : ErrorTests<SystemSqlClientProvider>(Log) { }

#if MSSQLCLIENT
[Collection("ErrorTests")]
public sealed class MicrosoftSqlClientErrorTests(ITestOutputHelper Log) : ErrorTests<MicrosoftSqlClientProvider>(Log) { }
#endif
public abstract class ErrorTests<TProvider>(ITestOutputHelper Log) : TestBase<TProvider>
where TProvider : DatabaseProvider
{
// from https://github.com/DapperLib/Dapper/issues/2077
const string SQL = """
-- MOVE the 'SELECT 7;'-Statement here, to increase the required while(read()) calls by one.

BEGIN TRANSACTION
BEGIN TRY
SELECT 7; --SELECT any value INSIDE TRANSACTION

--FORCE Error
DECLARE @intvar INT
SET @intvar = 'A'
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
;THROW 50000, 'ERROR in Transaction', 1;
END CATCH
""";

[Theory]
[InlineData(CommandBehavior.Default)] // pass
[InlineData(CommandBehavior.SingleResult, 0, 0)] // fail
[InlineData(CommandBehavior.SingleResult, 1, 0)] // fail
[InlineData(CommandBehavior.SingleResult, 2, 0)] // pass - two extra Read helps
[InlineData(CommandBehavior.SingleResult, 3, 0)] // pass
[InlineData(CommandBehavior.SingleResult, 0, 10)] // fail - no number of NextResult helps
[InlineData(CommandBehavior.SingleRow, 0, 0)] // fail
[InlineData(CommandBehavior.SingleRow, 1, 0)] // fail
[InlineData(CommandBehavior.SingleRow, 2, 0)] // pass - two extra Read helps
[InlineData(CommandBehavior.SingleRow, 3, 0)] // pass
[InlineData(CommandBehavior.SingleRow, 0, 10)] // fail - no number of NextResult helps
[InlineData(CommandBehavior.SingleRow | CommandBehavior.SingleResult, 0, 0)] // fail
[InlineData(CommandBehavior.SingleRow | CommandBehavior.SingleResult, 1, 0)] // fail
[InlineData(CommandBehavior.SingleRow | CommandBehavior.SingleResult, 2, 0)] // pass - two extra Read helps
[InlineData(CommandBehavior.SingleRow | CommandBehavior.SingleResult, 3, 0)] // pass
[InlineData(CommandBehavior.SingleRow | CommandBehavior.SingleResult, 0, 10)] // fail - no number of NextResult helps
public void ManualADONET(CommandBehavior commandBehavior, int extraRowReads = 0, int extraGridReads = 0)
{
using var conn = GetOpenConnection();
using var cmd = conn.CreateCommand();
cmd.CommandText = SQL;
using var reader = cmd.ExecuteReader(commandBehavior);

var ex = AssertType(Assert.ThrowsAny<DbException>(() =>
{
int grid = 0;
do
{
int row = 0;
if (reader.Read())
{
int width = reader.FieldCount;
do
{
for (int col = 0; col < width; col++)
{
var val = reader.GetValue(col);
Console.WriteLine($"[{grid}, {row}, {col}] {val}");
}
row++;
}
while (reader.Read());
for (int i = 0; i < extraRowReads; i++)
{
_ = reader.Read();
}
}
grid++;
}
while (reader.NextResult());
for (int i = 0; i < extraGridReads; i++)
{
_ = reader.NextResult();
}
}));
Log.WriteLine(ex.Message);

}

[Fact]
public async Task ExceptionTestAsync()
{
var ex = AssertType(await Assert.ThrowsAnyAsync<DbException>(async () =>
{
#if !NET472
await
#endif
using var connection = GetClosedConnection();
_ = await connection.QueryFirstOrDefaultAsync<int>(SQL);
}));
Log.WriteLine(ex.Message);
}
[Fact]
public void ExceptionTest()
{
var ex = AssertType(Assert.ThrowsAny<DbException>(() =>
{
using var connection = GetClosedConnection();
_ = connection.QueryFirstOrDefault<int>(SQL);
}));
Log.WriteLine(ex.Message);
}
}
1 change: 1 addition & 0 deletions tests/Dapper.Tests/Providers/DuckDBTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class DuckDBProvider : DatabaseProvider
{
public override DbProviderFactory Factory => DuckDBClientFactory.Instance;
public override string GetConnectionString() => "Data Source=:memory:";
public override Type ExceptionType => typeof(DuckDBException);
}

public abstract class DuckDBTypeTestBase : TestBase<DuckDBProvider>
Expand Down
6 changes: 4 additions & 2 deletions tests/Dapper.Tests/Providers/FirebirdTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using FirebirdSql.Data.FirebirdClient;
using System.Data;
using System;
using System.Data.Common;
using System.Linq;
using FirebirdSql.Data.FirebirdClient;
using Xunit;

namespace Dapper.Tests.Providers
Expand All @@ -16,6 +16,8 @@ public class FirebirdProvider : DatabaseProvider
{
public override DbProviderFactory Factory => FirebirdClientFactory.Instance;
public override string GetConnectionString() => "initial catalog=localhost:database;user id=SYSDBA;password=masterkey";

public override Type ExceptionType => typeof(DbException);
}
public class FirebirdTests : TestBase<FirebirdProvider>
{
Expand Down
2 changes: 2 additions & 0 deletions tests/Dapper.Tests/Providers/MySQLTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public sealed class MySqlProvider : DatabaseProvider
public override string GetConnectionString() =>
GetConnectionString("MySqlConnectionString", "Server=localhost;Database=tests;Uid=test;Pwd=pass;");

public override Type ExceptionType => typeof(MySqlConnector.MySqlException);

public DbConnection GetMySqlConnection(bool open = true,
bool convertZeroDatetime = false, bool allowZeroDatetime = false)
{
Expand Down
1 change: 1 addition & 0 deletions tests/Dapper.Tests/Providers/OLDEBTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class OLEDBProvider : DatabaseProvider
public override DbProviderFactory Factory => OleDbFactory.Instance;
public override string GetConnectionString() =>
GetConnectionString("OLEDBConnectionString", "Provider=SQLOLEDB;Data Source=.;Initial Catalog=tempdb;Integrated Security=SSPI");
public override Type ExceptionType => typeof(OleDbException);
}

public class OLDEBTests : TestBase<OLEDBProvider>
Expand Down
2 changes: 2 additions & 0 deletions tests/Dapper.Tests/Providers/PostgresqlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class PostgresProvider : DatabaseProvider
public override DbProviderFactory Factory => Npgsql.NpgsqlFactory.Instance;
public override string GetConnectionString() =>
GetConnectionString("PostgesConnectionString", "Server=localhost;Port=5432;User Id=dappertest;Password=dapperpass;Database=dappertest");

public override Type ExceptionType => typeof(Npgsql.NpgsqlException);
}
public class PostgresqlTests : TestBase<PostgresProvider>
{
Expand Down
2 changes: 2 additions & 0 deletions tests/Dapper.Tests/Providers/SqliteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class SqliteProvider : DatabaseProvider
{
public override DbProviderFactory Factory => SqliteFactory.Instance;
public override string GetConnectionString() => "Data Source=:memory:";

public override Type ExceptionType => typeof(SqliteException);
}

public abstract class SqliteTypeTestBase : TestBase<SqliteProvider>
Expand Down
10 changes: 10 additions & 0 deletions tests/Dapper.Tests/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public abstract class DatabaseProvider
{
public abstract DbProviderFactory Factory { get; }

public abstract Type ExceptionType { get; }

public virtual void Dispose() { }
public abstract string GetConnectionString();

Expand Down Expand Up @@ -75,11 +77,13 @@ public DbConnection GetOpenConnection(bool mars)
public sealed class SystemSqlClientProvider : SqlServerDatabaseProvider
{
public override DbProviderFactory Factory => System.Data.SqlClient.SqlClientFactory.Instance;
public override Type ExceptionType => typeof(System.Data.SqlClient.SqlException);
}
#if MSSQLCLIENT
public sealed class MicrosoftSqlClientProvider : SqlServerDatabaseProvider
{
public override DbProviderFactory Factory => Microsoft.Data.SqlClient.SqlClientFactory.Instance;
public override Type ExceptionType => typeof(Microsoft.Data.SqlClient.SqlException);
}
#endif

Expand Down Expand Up @@ -122,6 +126,12 @@ static TestBase()
}
}

public DbException AssertType(DbException exception)
{
Assert.IsAssignableFrom(Provider.ExceptionType, exception);
return exception;
}

public virtual void Dispose()
{
_connection?.Dispose();
Expand Down

0 comments on commit cc3d542

Please sign in to comment.