Skip to content

[5.2] Port PR 2896 (Allow errors with negative numbers to be considered transient) #3089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -314,7 +314,7 @@ private static ICollection<int> SplitErrorNumberList(string list)
HashSet<int> set = new HashSet<int>();
for (int index = 0; index < parts.Length; index++)
{
if (int.TryParse(parts[index], System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowTrailingWhite, null, out int value))
if (int.TryParse(parts[index], System.Globalization.NumberStyles.Integer, null, out int value))
{
set.Add(value);
}
Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@ public class RetryLogicConfigHelper

private const string SqlRetryLogicTypeName = "Microsoft.Data.SqlClient.SqlRetryLogic";

private const string CreateExceptionMethodName = "CreateException";
private const string AddMethodName = "Add";

public const string DefaultTransientErrors = "1204, 1205, 1222, 49918, 49919, 49920, 4060, 4221, 40143, 40613, 40501, 40540, 40197, 42108, 42109, 10929, 10928, 10060, 10054, 10053, 997, 233, 64, 20, 0, -2, 207, 102, 2812";

private static readonly Random s_random = new Random();
@@ -36,13 +39,23 @@ public class RetryLogicConfigHelper
private static readonly Type s_appContextSwitchManagerType = s_sqlClientAssembly.GetType(AppContextSwitchManagerTypeName);
private static readonly Type s_sqlretrylogicType = s_sqlClientAssembly.GetType(SqlRetryLogicTypeName);
private static readonly Type s_configurationLoaderType = s_sqlClientAssembly.GetType(ConfigurationLoaderTypeName);
private static readonly Type s_sqlErrorType = typeof(SqlError);
private static readonly Type s_sqlErrorCollectionType = typeof(SqlErrorCollection);
private static readonly Type[] s_cfgLoaderParamsType = new Type[]
{
s_sqlClientAssembly.GetType(InterfaceCnnCfgTypeName),
s_sqlClientAssembly.GetType(InterfaceCmdCfgTypeName),
typeof(string), typeof(string)
};
private static readonly Type[] s_sqlErrorParamsType = new Type[]
{
typeof(int), typeof(byte), typeof(byte),
typeof(string), typeof(string), typeof(string),
typeof(int), typeof(Exception)
};
private static readonly ConstructorInfo s_loaderCtorInfo = s_configurationLoaderType.GetConstructor(s_cfgLoaderParamsType);
private static readonly ConstructorInfo s_sqlErrorCtorInfo = s_sqlErrorType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, s_sqlErrorParamsType, null);
private static readonly ConstructorInfo s_sqlErrorCollectionCtorInfo = s_sqlErrorCollectionType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

public static object CreateLoader(RetryLogicConfigs cnnConfig, RetryLogicConfigs cmdConfig)
{
@@ -164,6 +177,22 @@ public static RetryLogicConfigs CreateRandomConfig(string method, string authori
};
}

public static SqlException CreateSqlException(int errorNumber)
{
MethodInfo addSqlErrorMethod = typeof(SqlErrorCollection).GetMethod(AddMethodName, BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo createExceptionMethod = typeof(SqlException).GetMethod(CreateExceptionMethodName, BindingFlags.Static | BindingFlags.NonPublic,
null, new Type[] { typeof(SqlErrorCollection), typeof(string) }, null);

SqlError sqlError = s_sqlErrorCtorInfo.Invoke(new object[] { errorNumber, (byte)0, (byte)0, string.Empty, string.Empty, string.Empty, 0, null }) as SqlError;
SqlErrorCollection sqlErrorCollection = s_sqlErrorCollectionCtorInfo.Invoke(new object[0] { }) as SqlErrorCollection;

addSqlErrorMethod.Invoke(sqlErrorCollection, new object[] { sqlError });

SqlException sqlException = createExceptionMethod.Invoke(null, new object[] { sqlErrorCollection, string.Empty }) as SqlException;

return sqlException;
}

private static TimeSpan GenerateTimeSpan(TimeSpan start, TimeSpan end)
{
int max = (int)(end - start).TotalSeconds;
Original file line number Diff line number Diff line change
@@ -222,6 +222,30 @@ public void InvalidTransientError(string errors)
}
#endregion

#region Valid Configurations
[Theory]
[InlineData("-1,1,2,3")]
[InlineData("-1, 1, 2 , 3, -2")]
[InlineData("")]
public void ValidTransientError(string errors)
{
string[] transientErrorNumbers = errors.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
RetryLogicConfigs cnnCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix);
cnnCfg.TransientErrors = errors;
RetryLogicConfigs cmdCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix, @"Don't care!");

RetryLogicConfigHelper.ReturnLoaderAndProviders(cnnCfg, cmdCfg, out SqlRetryLogicBaseProvider cnnProvider, out _);

foreach(string errorString in transientErrorNumbers)
{
int errorNumber = int.Parse(errorString.Trim());
SqlException transientException = RetryLogicConfigHelper.CreateSqlException(errorNumber);

Assert.True(cnnProvider.RetryLogic.TransientPredicate(transientException), $"Error {errorNumber} is not considered transient by the predicate.");
}
}
#endregion

#region private methods
private void TestConnection(SqlRetryLogicBaseProvider provider, RetryLogicConfigs cnfig)
{

Unchanged files with check annotations Beta

<Target Name="RunManualTests">
<!-- Windows -->
<Exec ConsoleToMsBuild="true" Command="$(DotnetPath)dotnet test &quot;@(ManualTestsProj)&quot; -p:Configuration=$(Configuration) -p:Target$(TFGroup)Version=$(TF) --no-build -l &quot;console;verbosity=normal&quot; --collect &quot;Code coverage&quot; -p:TestSet=$(TestSet) --results-directory $(ResultsDirectory) -p:TestTargetOS=Windows$(TargetGroup) --filter &quot;category!=non$(TargetGroup)tests&amp;category!=failing&amp;category!=nonwindowstests&quot; &quot;--logger:trx;LogFilePrefix=Manual-Windows$(TargetGroup)-$(TestSet)&quot;" Condition="'$(IsEnabledWindows)' == 'true'"/>

Check failure on line 189 in build.proj

Azure Pipelines / Release 5.2 (Win 2022 ARM64 Azure SQL net8.0,AnyCPU,true,2,netstandard2.1)

build.proj#L189

build.proj(189,5): Error MSB3073: The command "dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=2 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-2"" exited with code 1.

Check failure on line 189 in build.proj

Azure Pipelines / Release 5.2 (Win 2022 ARM64 Azure SQL net8.0,AnyCPU,true,2,netstandard2.1)

build.proj#L189

build.proj(189,5): Error MSB3073: The command "dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=2 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-2"" exited with code 1.

Check failure on line 189 in build.proj

Azure Pipelines / Release 5.2 (Win 2022 ARM64 Azure SQL net8.0,AnyCPU,true,3,netstandard2.1)

build.proj#L189

build.proj(189,5): Error MSB3073: The command "C:\x86\dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=3 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-3"" exited with code 1.

Check failure on line 189 in build.proj

Azure Pipelines / Release 5.2 (Win 2022 SQL 2022 Instance Name net8.0,AnyCPU,false,1,netstandard2.1)

build.proj#L189

build.proj(189,5): Error MSB3073: The command "dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=1 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-1"" exited with code 1.

Check failure on line 189 in build.proj

Azure Pipelines / Release 5.2

build.proj#L189

build.proj(189,5): Error MSB3073: The command "C:\x86\dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration=Release -p:TargetnetcoreVersion=net8.0 --no-build -l "console;verbosity=normal" --collect "Code coverage" -p:TestSet=3 --results-directory TestResults -p:TestTargetOS=Windowsnetcoreapp --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" "--logger:trx;LogFilePrefix=Manual-Windowsnetcoreapp-3"" exited with code 1.
<!-- Unix -->
<Exec ConsoleToMsBuild="true" Command="$(DotnetPath)dotnet test &quot;@(ManualTestsProj)&quot; -p:Configuration=$(Configuration) -p:TargetNetCoreVersion=$(TF) --no-build -l &quot;console;verbosity=normal&quot; --collect &quot;Code coverage&quot; -p:TestSet=$(TestSet) --results-directory $(ResultsDirectory) -p:TestTargetOS=Unixnetcoreapp --filter &quot;category!=nonnetcoreapptests&amp;category!=failing&amp;category!=nonlinuxtests&amp;category!=nonuaptests&quot; &quot;--logger:trx;LogFilePrefix=Manual-Unixnetcoreapp-$(TestSet)&quot;" Condition="'$(IsEnabledWindows)' != 'true'"/>
</Target>