Skip to content

Commit 55aa1ee

Browse files
authored
Tests | Fix Tests regarding Concurrency both Sync and Async versions. (#2279)
1 parent eb68e1b commit 55aa1ee

File tree

1 file changed

+111
-124
lines changed

1 file changed

+111
-124
lines changed

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlCommandReliabilityTest.cs

Lines changed: 111 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Collections.Generic;
67
using System.Data;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -11,10 +12,37 @@
1112

1213
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
1314
{
14-
public class SqlCommandReliabilityTest
15+
public class SqlCommandReliabilityTest : IDisposable
1516
{
17+
private const int ConcurrentParallelExecutions = 3;
18+
private const string UnexpectedSqlConnectionExceptionMessage = "An unexpected SQL Connection Error occured and is not part of the test.";
1619
private readonly string _exceedErrMsgPattern = RetryLogicTestHelper.s_exceedErrMsgPattern;
1720
private readonly string _cancelErrMsgPattern = RetryLogicTestHelper.s_cancelErrMsgPattern;
21+
private readonly int _originalWorkerThreads;
22+
private readonly int _originalCompletionPortThreads;
23+
private bool _disposed = false;
24+
25+
public SqlCommandReliabilityTest()
26+
{
27+
ThreadPool.GetMinThreads(out _originalWorkerThreads, out _originalCompletionPortThreads);
28+
ThreadPool.SetMinThreads(ConcurrentParallelExecutions * 2, ConcurrentParallelExecutions * 2); // Multiply by 2 for possible additional threads needed in functions
29+
}
30+
31+
// Dispose Pattern
32+
public void Dispose()
33+
{
34+
Dispose(true);
35+
GC.SuppressFinalize(this);
36+
}
37+
38+
protected virtual void Dispose(bool disposing)
39+
{
40+
if (!_disposed)
41+
{
42+
ThreadPool.SetMinThreads(_originalWorkerThreads, _originalCompletionPortThreads);
43+
_disposed = true;
44+
}
45+
}
1846

1947
#region Sync
2048
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
@@ -524,160 +552,119 @@ public async void RetryExecuteAsyncCancel(string cnnString, SqlRetryLogicBasePro
524552
[MemberData(nameof(RetryLogicTestHelper.GetConnectionAndRetryStrategyInvalidCommand), parameters: new object[] { 2 }, MemberType = typeof(RetryLogicTestHelper), DisableDiscoveryEnumeration = true)]
525553
public void ConcurrentExecution(string cnnString, SqlRetryLogicBaseProvider provider)
526554
{
527-
int numberOfTries = provider.RetryLogic.NumberOfTries;
528555
string query = "SELECT bad command";
529-
int retriesCount = 0;
530-
int concurrentExecution = 3;
531-
provider.Retrying += (s, e) => Interlocked.Increment(ref retriesCount);
556+
ProcessDataInParallel(cnnString, provider, query, cmd => cmd.ExecuteScalar());
557+
ProcessDataInParallel(cnnString, provider, query, cmd => cmd.ExecuteNonQuery());
558+
ProcessDataInParallel(cnnString, provider, query, cmd => cmd.ExecuteReader());
559+
ProcessDataInParallel(cnnString, provider, query, cmd => cmd.ExecuteXmlReader());
532560

533-
Parallel.For(0, concurrentExecution,
534-
i =>
561+
if (DataTestUtility.IsNotAzureSynapse())
535562
{
536-
using (SqlConnection cnn = new SqlConnection(cnnString))
537-
using (SqlCommand cmd = cnn.CreateCommand())
538-
{
539-
cnn.Open();
540-
cmd.RetryLogicProvider = provider;
541-
cmd.CommandText = query;
542-
Assert.Throws<AggregateException>(() => cmd.ExecuteScalar());
543-
}
544-
});
545-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
563+
query += " FOR XML AUTO";
564+
ProcessDataInParallel(cnnString, provider, query, cmd => cmd.ExecuteXmlReader());
565+
}
566+
}
546567

547-
retriesCount = 0;
548-
Parallel.For(0, concurrentExecution,
549-
i =>
568+
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
569+
[MemberData(nameof(RetryLogicTestHelper.GetConnectionAndRetryStrategyInvalidCommand), parameters: new object[] { 2 }, MemberType = typeof(RetryLogicTestHelper), DisableDiscoveryEnumeration = true)]
570+
public async void ConcurrentExecutionAsync(string cnnString, SqlRetryLogicBaseProvider provider)
571+
{
572+
string query = "SELECT bad command";
573+
await ProcessDataAsAsync(cnnString, provider, query, cmd => cmd.ExecuteScalarAsync());
574+
await ProcessDataAsAsync(cnnString, provider, query, cmd => cmd.ExecuteNonQueryAsync());
575+
await ProcessDataAsAsync(cnnString, provider, query, cmd => cmd.ExecuteReaderAsync());
576+
await ProcessDataAsAsync(cnnString, provider, query, cmd => cmd.ExecuteXmlReaderAsync());
577+
578+
if (DataTestUtility.IsNotAzureSynapse())
550579
{
551-
using (SqlConnection cnn = new SqlConnection(cnnString))
552-
using (SqlCommand cmd = cnn.CreateCommand())
580+
query += " FOR XML AUTO";
581+
await ProcessDataAsAsync(cnnString, provider, query, cmd => cmd.ExecuteXmlReaderAsync());
582+
}
583+
}
584+
#endregion
585+
586+
#region private members
587+
private SqlCommand CreateCommand(SqlConnection cnn, SqlRetryLogicBaseProvider provider, int cancelAfterRetries)
588+
{
589+
cnn.Open();
590+
SqlCommand cmd = cnn.CreateCommand();
591+
cmd.RetryLogicProvider = provider;
592+
cmd.RetryLogicProvider.Retrying += (object s, SqlRetryingEventArgs e) =>
593+
{
594+
Assert.Equal(e.RetryCount, e.Exceptions.Count);
595+
Assert.NotEqual(TimeSpan.Zero, e.Delay);
596+
597+
if (e.RetryCount >= cancelAfterRetries)
553598
{
554-
cnn.Open();
555-
cmd.RetryLogicProvider = provider;
556-
cmd.CommandText = query;
557-
Assert.Throws<AggregateException>(() => cmd.ExecuteNonQuery());
599+
e.Cancel = true;
558600
}
559-
});
560-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
601+
};
602+
return cmd;
603+
}
561604

562-
retriesCount = 0;
563-
Parallel.For(0, concurrentExecution,
605+
private static void ProcessDataInParallel(string cnnString, SqlRetryLogicBaseProvider provider,
606+
string query, Action<SqlCommand> commandAction)
607+
{
608+
int numberOfTries = provider.RetryLogic.NumberOfTries;
609+
int retryExceptionCount = 0;
610+
611+
Parallel.For(0, ConcurrentParallelExecutions,
564612
i =>
565613
{
566614
using (SqlConnection cnn = new SqlConnection(cnnString))
567-
using (SqlCommand cmd = cnn.CreateCommand())
568615
{
569616
cnn.Open();
570-
cmd.RetryLogicProvider = provider;
571-
cmd.CommandText = query;
572-
Assert.Throws<AggregateException>(() => cmd.ExecuteReader());
573-
}
574-
});
575-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
617+
Assert.True(cnn.State == ConnectionState.Open, UnexpectedSqlConnectionExceptionMessage);
576618

577-
if(DataTestUtility.IsNotAzureSynapse())
578-
{
579-
retriesCount = 0;
580-
Parallel.For(0, concurrentExecution,
581-
i =>
582-
{
583-
using (SqlConnection cnn = new SqlConnection(cnnString))
584619
using (SqlCommand cmd = cnn.CreateCommand())
585620
{
586-
cnn.Open();
587621
cmd.RetryLogicProvider = provider;
588-
cmd.CommandText = query + " FOR XML AUTO";
589-
Assert.Throws<AggregateException>(() => cmd.ExecuteXmlReader());
622+
cmd.CommandText = query;
623+
624+
AggregateException retryAggregateException = Assert.Throws<AggregateException>(() => commandAction(cmd));
625+
Interlocked.Add(ref retryExceptionCount, retryAggregateException.InnerExceptions?.Count ?? 0);
590626
}
591-
});
592-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
593-
}
594-
595-
retriesCount = 0;
596-
Parallel.For(0, concurrentExecution,
597-
i =>
598-
{
599-
using (SqlConnection cnn = new SqlConnection(cnnString))
600-
using (SqlCommand cmd = cnn.CreateCommand())
601-
{
602-
cnn.Open();
603-
cmd.RetryLogicProvider = provider;
604-
cmd.CommandText = query;
605-
Assert.ThrowsAsync<AggregateException>(() => cmd.ExecuteScalarAsync()).Wait();
606627
}
607628
});
608-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
609629

610-
retriesCount = 0;
611-
Parallel.For(0, concurrentExecution,
612-
i =>
613-
{
614-
using (SqlConnection cnn = new SqlConnection(cnnString))
615-
using (SqlCommand cmd = cnn.CreateCommand())
616-
{
617-
cnn.Open();
618-
cmd.RetryLogicProvider = provider;
619-
cmd.CommandText = query;
620-
Assert.ThrowsAsync<AggregateException>(() => cmd.ExecuteNonQueryAsync()).Wait();
621-
}
622-
});
623-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
630+
// Assertion for Retries
631+
int expectedTotalNumberOfRetries = numberOfTries * ConcurrentParallelExecutions;
632+
Assert.Equal(expectedTotalNumberOfRetries, retryExceptionCount);
633+
}
624634

625-
retriesCount = 0;
626-
Parallel.For(0, concurrentExecution,
627-
i =>
628-
{
629-
using (SqlConnection cnn = new SqlConnection(cnnString))
630-
using (SqlCommand cmd = cnn.CreateCommand())
631-
{
632-
cnn.Open();
633-
cmd.RetryLogicProvider = provider;
634-
cmd.CommandText = query;
635-
Assert.ThrowsAsync<AggregateException>(() => cmd.ExecuteReaderAsync()).Wait();
636-
}
637-
});
638-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
635+
private static async Task ProcessDataAsAsync(string cnnString, SqlRetryLogicBaseProvider provider,
636+
string query, Func<SqlCommand, Task> commandAction)
637+
{
638+
int numberOfTries = provider.RetryLogic.NumberOfTries;
639+
int retryExceptionCount = 0;
639640

640-
// TODO: there is a known issue by ExecuteXmlReaderAsync that should be solved first- issue #44
641-
/*
642-
643-
if(DataTestUtility.IsNotAzureSynapse())
641+
List<Task> tasks = new List<Task>();
642+
for (int i = 0; i < ConcurrentParallelExecutions; i++)
644643
{
645-
retriesCount = 0;
646-
Parallel.For(0, concurrentExecution,
647-
i =>
644+
tasks.Add(Task.Run(async () =>
648645
{
649646
using (SqlConnection cnn = new SqlConnection(cnnString))
650-
using (SqlCommand cmd = cnn.CreateCommand())
651647
{
652-
cnn.Open();
653-
cmd.RetryLogicProvider = provider;
654-
cmd.CommandText = query + " FOR XML AUTO";
655-
Assert.ThrowsAsync<AggregateException>(() => cmd.ExecuteXmlReaderAsync()).Wait();
648+
await cnn.OpenAsync();
649+
Assert.True(cnn.State == ConnectionState.Open, UnexpectedSqlConnectionExceptionMessage);
650+
651+
using (SqlCommand cmd = cnn.CreateCommand())
652+
{
653+
cmd.RetryLogicProvider = provider;
654+
cmd.CommandText = query;
655+
656+
AggregateException retryAggregateException = await Assert.ThrowsAsync<AggregateException>(async () => await commandAction(cmd));
657+
Interlocked.Add(ref retryExceptionCount, retryAggregateException.InnerExceptions?.Count ?? 0);
658+
}
656659
}
657-
});
658-
Assert.Equal(numberOfTries * concurrentExecution, retriesCount + concurrentExecution);
660+
}));
659661
}
660-
*/
661-
}
662-
#endregion
663662

664-
#region private members
665-
private SqlCommand CreateCommand(SqlConnection cnn, SqlRetryLogicBaseProvider provider, int cancelAfterRetries)
666-
{
667-
cnn.Open();
668-
SqlCommand cmd = cnn.CreateCommand();
669-
cmd.RetryLogicProvider = provider;
670-
cmd.RetryLogicProvider.Retrying += (object s, SqlRetryingEventArgs e) =>
671-
{
672-
Assert.Equal(e.RetryCount, e.Exceptions.Count);
673-
Assert.NotEqual(TimeSpan.Zero, e.Delay);
663+
await Task.WhenAll(tasks);
674664

675-
if (e.RetryCount >= cancelAfterRetries)
676-
{
677-
e.Cancel = true;
678-
}
679-
};
680-
return cmd;
665+
// Assertion for Retries
666+
int expectedTotalNumberOfRetries = numberOfTries * ConcurrentParallelExecutions;
667+
Assert.Equal(expectedTotalNumberOfRetries, retryExceptionCount);
681668
}
682669
#endregion
683670
}

0 commit comments

Comments
 (0)