From b79917a4618a2aa5b7576d692ba06162ee7c1848 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 10 Dec 2025 13:59:59 -0600 Subject: [PATCH 1/8] Split async cancelled connection test into mars and no-mars tests --- .../AsyncTest/AsyncCancelledConnectionsTest.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs index 0ae12be917..863be40f73 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs @@ -24,13 +24,16 @@ public AsyncCancelledConnectionsTest(ITestOutputHelper output) } // Disabled on Azure since this test fails on concurrent runs on same database. - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] - public void CancelAsyncConnections() + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] + [InlineData(true)] + [InlineData(false)] + public void CancelAsyncConnections(bool useMars) { + // Arrange SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString); - builder.MultipleActiveResultSets = false; - RunCancelAsyncConnections(builder); - builder.MultipleActiveResultSets = true; + builder.MultipleActiveResultSets = useMars; + + // Act RunCancelAsyncConnections(builder); } @@ -59,15 +62,18 @@ private void RunCancelAsyncConnections(SqlConnectionStringBuilder connectionStri { _output.WriteLine(ex.ToString()); } + while (!results.IsCompleted) { Thread.Sleep(50); } + DisplaySummary(); foreach (var detail in _exceptionDetails) { _output.WriteLine(detail); } + Assert.Empty(_exceptionDetails); } From 2007b210ca8e9e46a27455f47fb6bc762ff645ee Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 10 Dec 2025 17:58:55 -0600 Subject: [PATCH 2/8] Small improvements to AsyncCancelledConnectionsTest to run async and fail fast on any unexpected exception --- .../AsyncCancelledConnectionsTest.cs | 91 ++++++++----------- 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs index 863be40f73..c7fb75ead9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading; @@ -27,54 +26,37 @@ public AsyncCancelledConnectionsTest(ITestOutputHelper output) [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] [InlineData(true)] [InlineData(false)] - public void CancelAsyncConnections(bool useMars) + public async Task CancelAsyncConnections(bool useMars) { // Arrange SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString); builder.MultipleActiveResultSets = useMars; // Act - RunCancelAsyncConnections(builder); + await RunCancelAsyncConnections(builder); } - private void RunCancelAsyncConnections(SqlConnectionStringBuilder connectionStringBuilder) + private async Task RunCancelAsyncConnections(SqlConnectionStringBuilder connectionStringBuilder) { SqlConnection.ClearAllPools(); - - ParallelLoopResult results = new ParallelLoopResult(); - ConcurrentDictionary tracker = new ConcurrentDictionary(); + + var tracker = new ConcurrentDictionary(); _random = new Random(4); // chosen via fair dice roll. _watch = Stopwatch.StartNew(); - try + using (new Timer(TimerCallback, state: null, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5))) { - // Setup a timer so that we can see what is going on while our tasks run - using (new Timer(TimerCallback, state: null, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5))) + Task[] tasks = new Task[NumberOfTasks]; + for (int i = 0; i < tasks.Length; i++) { - results = Parallel.For( - fromInclusive: 0, - toExclusive: NumberOfTasks, - (int i) => DoManyAsync(i, tracker, connectionStringBuilder).GetAwaiter().GetResult()); + tasks[i] = DoManyAsync(i, tracker, connectionStringBuilder); } - } - catch (Exception ex) - { - _output.WriteLine(ex.ToString()); - } - while (!results.IsCompleted) - { - Thread.Sleep(50); + await Task.WhenAll(tasks); } DisplaySummary(); - foreach (var detail in _exceptionDetails) - { - _output.WriteLine(detail); - } - - Assert.Empty(_exceptionDetails); } // Display one row every 5'ish seconds @@ -88,12 +70,7 @@ private void TimerCallback(object state) private void DisplaySummary() { - int count; - lock (_exceptionDetails) - { - count = _exceptionDetails.Count; - } - _output.WriteLine($"{_watch.Elapsed} {_continue} Started:{_start} Done:{_done} InFlight:{_inFlight} RowsRead:{_rowsRead} ResultRead:{_resultRead} PoisonedEnded:{_poisonedEnded} nonPoisonedExceptions:{_nonPoisonedExceptions} PoisonedCleanupExceptions:{_poisonCleanUpExceptions} Count:{count} Found:{_found}"); + _output.WriteLine($"{_watch.Elapsed} {_continue} Started:{_start} Done:{_done} InFlight:{_inFlight} RowsRead:{_rowsRead} ResultRead:{_resultRead} PoisonedEnded:{_poisonedEnded} nonPoisonedExceptions:{_nonPoisonedExceptions} PoisonedCleanupExceptions:{_poisonCleanUpExceptions} Found:{_found}"); } // This is the the main body that our Tasks run @@ -155,36 +132,46 @@ private async Task DoOneAsync(SqlConnection marsConnection, string connectionStr } } } + catch (Exception ex) when (poison && IsExpectedCancellation(ex)) + { + // Expected cancellation from the time bomb when poisoning. + } catch (Exception ex) { if (!poison) { Interlocked.Increment(ref _nonPoisonedExceptions); - - string details = ex.ToString(); - details = details.Substring(0, Math.Min(200, details.Length)); - lock (_exceptionDetails) - { - _exceptionDetails.Add(details); - } } if (ex.Message.Contains("The MARS TDS header contained errors.")) { _continue = false; - if (_found == 0) // This check is not really safe we may list more than one. + lock (_lockObject) { - lock (_lockObject) - { - // You will notice that poison will be likely be false here, it is the normal commands that suffer - // Once we have successfully poisoned the connection pool, we may start to see some other request to poison fail just like the normal requests - _output.WriteLine($"{poison} {DateTime.UtcNow.ToString("O")}"); - _output.WriteLine(ex.ToString()); - } + _output.WriteLine($"{poison} {DateTime.UtcNow.ToString("O")}"); + _output.WriteLine(ex.ToString()); } Interlocked.Increment(ref _found); } + + throw; + } + } + + private static bool IsExpectedCancellation(Exception ex) + { + if (ex is OperationCanceledException) + { + return true; + } + + if (ex is SqlException sqlEx) + { + return sqlEx.Message.IndexOf("operation cancelled", StringComparison.OrdinalIgnoreCase) >= 0 + || sqlEx.Message.IndexOf("operation canceled", StringComparison.OrdinalIgnoreCase) >= 0; } + + return false; } private async Task RunCommand(SqlConnection connection, string commandText, bool poison, int parent) @@ -239,10 +226,6 @@ private async Task RunCommand(SqlConnection connection, string commandText, bool throw; } - catch (Exception ex) - { - Assert.Fail("unexpected exception: " + ex.GetType().Name + " " +ex.Message); - } } } finally @@ -298,7 +281,5 @@ private async Task SleepAsync(int minMs, int maxMs) private int _found; private Random _random; private object _lockObject = new object(); - - private HashSet _exceptionDetails = new HashSet(); } } From 7178c34192571dff02f15d424a9c7a931ea6e935 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 11 Dec 2025 13:29:06 -0600 Subject: [PATCH 3/8] Introduce extensions for SqlDataReader [MOVE] --- .../tests/Common/SqlDataReaderExtensions.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs diff --git a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs new file mode 100644 index 0000000000..43c7bde4bd --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.SqlClient.Tests.Common +{ + /// + /// Extensions on the class. + /// + public static class SqlDataReaderExtensions + { + /// + /// Reads all result sets in the provided and discards them. + /// + /// Reader to flush results from. + public static void FlushAllResults(this SqlDataReader dataReader) + { + do + { + dataReader.FlushResultSet(); + } while (dataReader.NextResult()); + } + + /// + /// Reads all results in the current result set of the provided + /// and discards them. + /// + /// Reader to flush results from. + public static void FlushResultSet(this SqlDataReader dataReader) + { + while (dataReader.Read()) + { + // Discard results. + } + } + } +} From a089396ee32e5fcbf9237fb50cfada40292a9c13 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 11 Dec 2025 13:30:40 -0600 Subject: [PATCH 4/8] Split XEventScope into separate file --- .../ManualTests/DataCommon/DataTestUtility.cs | 185 ---------------- .../ManualTests/DataCommon/XEventScope.cs | 204 ++++++++++++++++++ ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../SQL/DataStreamTest/DataStreamTest.cs | 11 +- 4 files changed, 210 insertions(+), 191 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 7b1fb3bc30..1991951591 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -1295,191 +1295,6 @@ protected virtual void OnMatchingEventWritten(EventWrittenEventArgs eventData) #nullable enable - public readonly ref struct XEventScope : IDisposable - { - #region Private Fields - - // Maximum dispatch latency for XEvents, in seconds. - private const int MaxDispatchLatencySeconds = 5; - - // The connection to use for all operations. - private readonly SqlConnection _connection; - - // True if connected to an Azure SQL instance. - private readonly bool _isAzureSql; - - // True if connected to a non-Azure SQL Server 2025 (version 17) or - // higher. - private readonly bool _isVersion17OrHigher; - - // Duration for the XEvent session, in minutes. - private readonly ushort _durationInMinutes; - - #endregion - - #region Properties - - /// - /// The name of the XEvent session, derived from the session name - /// provided at construction time, with a unique suffix appended. - /// - public string SessionName { get; } - - #endregion - - #region Construction - - /// - /// Construct with the specified parameters. - /// - /// This will use the connection to query the server properties and - /// setup and start the XEvent session. - /// - /// The base name of the session. - /// The SQL connection to use. (Must already be open.) - /// The event specification T-SQL string. - /// The target specification T-SQL string. - /// The duration of the session in minutes. - public XEventScope( - string sessionName, - // The connection must already be open. - SqlConnection connection, - string eventSpecification, - string targetSpecification, - ushort durationInMinutes = 5) - { - SessionName = GenerateRandomCharacters(sessionName); - - _connection = connection; - Assert.Equal(ConnectionState.Open, _connection.State); - - _durationInMinutes = durationInMinutes; - - // EngineEdition 5 indicates Azure SQL. - _isAzureSql = GetSqlServerProperty(connection, ServerProperty.EngineEdition) == "5"; - - // Determine if we're connected to a SQL Server instance version - // 17 or higher. - if (!_isAzureSql) - { - int majorVersion; - Assert.True( - int.TryParse( - GetSqlServerProperty(connection, ServerProperty.ProductMajorVersion), - out majorVersion)); - _isVersion17OrHigher = majorVersion >= 17; - } - - // Setup and start the XEvent session. - string sessionLocation = _isAzureSql ? "DATABASE" : "SERVER"; - - // Both Azure SQL and SQL Server 2025+ support setting a maximum - // duration for the XEvent session. - string duration = - _isAzureSql || _isVersion17OrHigher - ? $"MAX_DURATION={_durationInMinutes} MINUTES," - : string.Empty; - - string xEventCreateAndStartCommandText = - $@"CREATE EVENT SESSION [{SessionName}] ON {sessionLocation} - {eventSpecification} - {targetSpecification} - WITH ( - {duration} - MAX_MEMORY=16 MB, - EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS, - MAX_DISPATCH_LATENCY={MaxDispatchLatencySeconds} SECONDS, - MAX_EVENT_SIZE=0 KB, - MEMORY_PARTITION_MODE=NONE, - TRACK_CAUSALITY=ON, - STARTUP_STATE=OFF) - - ALTER EVENT SESSION [{SessionName}] ON {sessionLocation} STATE = START "; - - using SqlCommand createXEventSession = new SqlCommand(xEventCreateAndStartCommandText, _connection); - createXEventSession.ExecuteNonQuery(); - } - - /// - /// Disposal stops and drops the XEvent session. - /// - /// - /// Disposal isn't perfect - tests can abort without cleaning up the - /// events they have created. For Azure SQL targets that outlive the - /// test pipelines, it is beneficial to periodically log into the - /// database and drop old XEvent sessions using T-SQL similar to - /// this: - /// - /// DECLARE @sql NVARCHAR(MAX) = N''; - /// - /// -- Identify inactive (stopped) event sessions and generate DROP commands - /// SELECT @sql += N'DROP EVENT SESSION [' + name + N'] ON SERVER;' + CHAR(13) + CHAR(10) - /// FROM sys.server_event_sessions - /// WHERE running = 0; -- Filter for sessions that are not running (inactive) - /// - /// -- Print the generated commands for review (optional, but recommended) - /// PRINT @sql; - /// - /// -- Execute the generated commands - /// EXEC sys.sp_executesql @sql; - /// - public void Dispose() - { - string dropXEventSessionCommand = _isAzureSql - // We choose the sys.(database|server)_event_sessions views - // here to ensure we find sessions that may not be running. - ? $"IF EXISTS (select * from sys.database_event_sessions where name ='{SessionName}')" + - $" DROP EVENT SESSION [{SessionName}] ON DATABASE" - : $"IF EXISTS (select * from sys.server_event_sessions where name ='{SessionName}')" + - $" DROP EVENT SESSION [{SessionName}] ON SERVER"; - - using SqlCommand command = new SqlCommand(dropXEventSessionCommand, _connection); - command.ExecuteNonQuery(); - } - - #endregion - - #region Public Methods - - /// - /// Query the XEvent session for its collected events, returning - /// them as an XML document. - /// - /// This always blocks the thread for MaxDispatchLatencySeconds to - /// ensure that all events have been flushed into the ring buffer. - /// - public System.Xml.XmlDocument GetEvents() - { - string xEventQuery = _isAzureSql - ? $@"SELECT xet.target_data - FROM sys.dm_xe_database_session_targets AS xet - INNER JOIN sys.dm_xe_database_sessions AS xe - ON (xe.address = xet.event_session_address) - WHERE xe.name = '{SessionName}'" - : $@"SELECT xet.target_data - FROM sys.dm_xe_session_targets AS xet - INNER JOIN sys.dm_xe_sessions AS xe - ON (xe.address = xet.event_session_address) - WHERE xe.name = '{SessionName}'"; - - using SqlCommand command = new SqlCommand(xEventQuery, _connection); - - // Wait for maximum dispatch latency to ensure all events - // have been flushed to the ring buffer. - Thread.Sleep(MaxDispatchLatencySeconds * 1000); - - string? targetData = command.ExecuteScalar() as string; - Assert.NotNull(targetData); - - System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument(); - - xmlDocument.LoadXml(targetData); - return xmlDocument; - } - - #endregion - } - /// /// Resolves the machine's fully qualified domain name if it is applicable. /// diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs new file mode 100644 index 0000000000..f682b68dce --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs @@ -0,0 +1,204 @@ +using System; +using System.Data; +using System.Threading; +using System.Xml; + +#nullable enable + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public readonly ref struct XEventScope : IDisposable + { + #region Private Fields + + /// + /// Maximum dispatch latency for XEvents, in seconds. + /// + private const int MaxDispatchLatencySeconds = 5; + + /// + /// The connection to use for all operations. + /// + private readonly SqlConnection _connection; + + /// + /// Duration for the XEvent session, in minutes. + /// + private readonly ushort _durationInMinutes; + + /// + /// true if connected to an Azure SQL instance. + /// + private readonly bool _isAzureSql; + + /// + /// true if connected to a non-Azure SQL Server 2025 (version 17) or higher. + /// + private readonly bool _isVersion17OrHigher; + + #endregion + + #region Construction + + /// + /// Construct with the specified parameters. + /// + /// This will use the connection to query the server properties and + /// setup and start the XEvent session. + /// + /// The base name of the session. + /// The SQL connection to use. (Must already be open.) + /// The event specification T-SQL string. + /// The target specification T-SQL string. + /// The duration of the session in minutes. + public XEventScope( + string sessionName, + SqlConnection connection, + string eventSpecification, + string targetSpecification, + ushort durationInMinutes = 5) + { + SessionName = DataTestUtility.GenerateRandomCharacters(sessionName); + + _connection = connection; + if (connection.State is not ConnectionState.Open) + { + throw new InvalidOperationException("Connection is not open"); + } + + _durationInMinutes = durationInMinutes; + + // EngineEdition 5 indicates Azure SQL. + _isAzureSql = DataTestUtility.GetSqlServerProperty(connection, DataTestUtility.ServerProperty.EngineEdition) == "5"; + if (!_isAzureSql) + { + // Determine if we're connected to a SQL Server instance version 17 or higher. + string majorVersionString = DataTestUtility.GetSqlServerProperty( + connection, + DataTestUtility.ServerProperty.ProductMajorVersion); + int majorVersionInt = int.Parse(majorVersionString); + + _isVersion17OrHigher = majorVersionInt >= 17; + } + + // Setup and start the XEvent session. + string sessionLocation = _isAzureSql ? "DATABASE" : "SERVER"; + + // Both Azure SQL and SQL Server 2025+ support setting a maximum duration for the + // XEvent session. + string duration = _isAzureSql || _isVersion17OrHigher + ? $"MAX_DURATION={_durationInMinutes} MINUTES," + : string.Empty; + + string xEventCreateAndStartCommandText = + $"CREATE EVENT SESSION [{SessionName}] ON {sessionLocation}" + + $" {eventSpecification} " + + $" {targetSpecification} " + + $"WITH (" + + $" {duration} " + + $" MAX_MEMORY=16 MB," + + $" EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS, " + + $" MAX_DISPATCH_LATENCY={MaxDispatchLatencySeconds} SECONDS, " + + $" MAX_EVENT_SIZE=0 KB, " + + $" MEMORY_PARTITION_MODE=NONE, " + + $" TRACK_CAUSALITY=ON, " + + $" STARTUP_STATE=OFF " + + $") " + + $"ALTER EVENT SESSION [{SessionName}] ON {sessionLocation} STATE = START "; + + using SqlCommand createXEventSession = new SqlCommand(xEventCreateAndStartCommandText, _connection); + createXEventSession.ExecuteNonQuery(); + } + + #endregion + + #region Properties + + /// + /// The name of the XEvent session, derived from the session name provided at construction + /// time, with a unique suffix appended. + /// + public string SessionName { get; } + + #endregion + + #region Public Methods + + /// + /// Disposal stops and drops the XEvent session. + /// + /// + /// Disposal isn't perfect - tests can abort without cleaning up the events they have + /// created. For Azure SQL targets that outlive the test pipelines, it is beneficial to + /// periodically log into the database and drop old XEvent sessions using T-SQL similar to + /// this: + /// + /// + /// DECLARE @sql NVARCHAR(MAX) = N''; + /// + /// -- Identify inactive (stopped) event sessions and generate DROP commands + /// SELECT @sql += N'DROP EVENT SESSION [' + name + N'] ON SERVER;' + CHAR(13) + CHAR(10) + /// FROM sys.server_event_sessions + /// WHERE running = 0; -- Filter for sessions that are not running (inactive) + /// + /// -- Print the generated commands for review (optional, but recommended) + /// PRINT @sql; + /// + /// -- Execute the generated commands + /// EXEC sys.sp_executesql @sql; + /// + /// + public void Dispose() + { + // We choose the sys.(database|server)_event_sessions views here to ensure we find + // sessions that may not be running. + string dropXEventSessionCommand = _isAzureSql + ? $"IF EXISTS (SELECT * FROM sys.database_event_sessions WHERE name='{SessionName}')" + + $" DROP EVENT SESSION [{SessionName}] ON DATABASE" + : $"IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name='{SessionName}')" + + $" DROP EVENT SESSION [{SessionName}] ON SERVER"; + + using SqlCommand command = new SqlCommand(dropXEventSessionCommand, _connection); + command.ExecuteNonQuery(); + } + + /// + /// Query the XEvent session for its collected events, returning them as an XML document. + /// + /// + /// This always blocks the thread for MaxDispatchLatencySeconds to ensure that all events + /// have been flushed into the ring buffer. + /// + /// Thrown if the query did not return a string result. + public XmlDocument GetEvents() + { + string xEventQuery = _isAzureSql + ? $"SELECT xet.target_data " + + $"FROM sys.dm_xe_database_session_targets AS xet " + + $" INNER JOIN sys.dm_xe_database_sessions AS xe" + + $" ON (xe.address = xet.event_session_address)" + + $"WHERE xe.name = '{SessionName}'" + : $"SELECT xet.target_data " + + $"FROM sys.dm_xe_session_targets AS xet " + + $" INNER JOIN sys.dm_xe_sessions AS xe " + + $" ON (xe.address = xet.event_session_address)" + + $"WHERE xe.name = '{SessionName}'"; + + using SqlCommand command = new SqlCommand(xEventQuery, _connection); + + // Wait for maximum dispatch latency to ensure all events have been flushed to the + // ring buffer. + Thread.Sleep(MaxDispatchLatencySeconds * 1000); + + string targetData = command.ExecuteScalar() as string + ?? throw new Exception("Command did not return a string result"); + + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(targetData); + + return xmlDocument; + } + + #endregion + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 6bc05a443e..dc454c2884 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -278,6 +278,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs index b4b7271216..74423f9f13 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs @@ -1959,12 +1959,11 @@ private void TestXEventsStreaming(string connectionString) using SqlConnection xEventManagementConnection = new SqlConnection(connectionString); xEventManagementConnection.Open(); - using DataTestUtility.XEventScope xEventScope = - new DataTestUtility.XEventScope( - _testName, - xEventManagementConnection, - "ADD EVENT sqlserver.user_event(ACTION(package0.event_sequence))", - "ADD TARGET package0.ring_buffer"); + using XEventScope xEventScope = new( + _testName, + xEventManagementConnection, + "ADD EVENT sqlserver.user_event(ACTION(package0.event_sequence))", + "ADD TARGET package0.ring_buffer"); string sessionName = xEventScope.SessionName; From 5b0d98c73c58a84907b3fc9922340e0aa9444881 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 11 Dec 2025 13:31:06 -0600 Subject: [PATCH 5/8] Rewrite mechaniism for extracting test name from ITest --- .../ManualTests/DataCommon/DataTestUtility.cs | 71 ++++++++----------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 1991951591..b3daa8dea1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -292,51 +292,38 @@ private static Task AcquireTokenAsync(string authorityURL, string userID #nullable enable /// - /// Returns the current test name as: - /// - /// ClassName.MethodName - /// - /// xUnit v2 doesn't provide access to a test context, so we use - /// reflection into the ITestOutputHelper to get the test name. + /// Returns the current test name as: ClassName.MethodName + /// xUnit v2 doesn't provide access to a test context, so we use reflection into the + /// ITestOutputHelper to get the test name. /// - /// - /// - /// The output helper instance for the currently running test. - /// - /// - /// The current test name. + /// + /// Thrown if any intermediate step of getting to the test name fails or is inaccessible. + /// + /// Output helper instance for the currently running test + /// Current test name public static string CurrentTestName(ITestOutputHelper outputHelper) { - // Reflect our way to the ITest instance. - var type = outputHelper.GetType(); - Assert.NotNull(type); - var testMember = type.GetField("test", BindingFlags.Instance | BindingFlags.NonPublic); - Assert.NotNull(testMember); - var test = testMember.GetValue(outputHelper) as ITest; - Assert.NotNull(test); - - // The DisplayName is in the format: - // - // Namespace.ClassName.MethodName(args) - // - // We only want the ClassName.MethodName portion. - // - Match match = TestNameRegex.Match(test.DisplayName); - Assert.True(match.Success); - // There should be 2 groups: the overall match, and the capture - // group. - Assert.Equal(2, match.Groups.Count); - - // The portion we want is in the capture group. - return match.Groups[1].Value; - } - - private static readonly Regex TestNameRegex = new( - // Capture the ClassName.MethodName portion, which may terminate - // the name, or have (args...) appended. - @"\.((?:[^.]+)\.(?:[^.\(]+))(?:\(.*\))?$", - RegexOptions.Compiled); - + // Reflect our way to the ITestMethod. + Type type = outputHelper.GetType(); + + FieldInfo testField = type.GetField("test", BindingFlags.Instance | BindingFlags.NonPublic) + ?? throw new Exception("Could not find field 'test' on ITestOutputHelper"); + + ITest test = testField.GetValue(outputHelper) as ITest + ?? throw new Exception("Field 'test' on outputHelper is null or not an ITest object."); + + ITestMethod testMethod = test.TestCase.TestMethod; + + // Class name will be fully-qualified. We only want the class name, so take the last part. + string[] testClassNameParts = testMethod.TestClass.Class.Name.Split('.'); + string testClassName = testClassNameParts[testClassNameParts.Length - 1]; + + string testMethodName = testMethod.Method.Name; + + // Reconstitute the test name as classname.methodname + return $"{testClassName}.{testMethodName}"; + } + /// /// SQL Server properties we can query. /// From 5a1273d65419c6c155479cb45e8b446bc361c398 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 11 Dec 2025 17:42:47 -0600 Subject: [PATCH 6/8] Patch up XEventTracingTest --- .../tests/ManualTests/TracingTests/XEventsTracingTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs index bcb23d11bd..ffd6c8ff79 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/XEventsTracingTest.cs @@ -40,7 +40,7 @@ public void XEventActivityIDConsistentWithTracing(string query, System.Data.Comm using SqlConnection xEventManagementConnection = new(DataTestUtility.TCPConnectionString); xEventManagementConnection.Open(); - using DataTestUtility.XEventScope xEventSession = new( + using XEventScope xEventSession = new( _testName, xEventManagementConnection, $@"ADD EVENT SQL_STATEMENT_STARTING (ACTION (client_connection_id) WHERE (client_connection_id='{connectionId}')), From c34905d337fc8d5d1bb9fb344cc42fd5b501be03 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Fri, 12 Dec 2025 13:45:24 -0600 Subject: [PATCH 7/8] Address copilot comments, strip out a lot of useless cruft in the async cancellation tests --- .../ManualTests/DataCommon/XEventScope.cs | 8 +- .../AsyncCancelledConnectionsTest.cs | 262 ++++++------------ 2 files changed, 93 insertions(+), 177 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs index f682b68dce..f87b36aa7a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs @@ -103,10 +103,10 @@ public XEventScope( $" MEMORY_PARTITION_MODE=NONE, " + $" TRACK_CAUSALITY=ON, " + $" STARTUP_STATE=OFF " + - $") " + + $"); " + $"ALTER EVENT SESSION [{SessionName}] ON {sessionLocation} STATE = START "; - using SqlCommand createXEventSession = new SqlCommand(xEventCreateAndStartCommandText, _connection); + using SqlCommand createXEventSession = new(xEventCreateAndStartCommandText, _connection); createXEventSession.ExecuteNonQuery(); } @@ -176,12 +176,12 @@ public XmlDocument GetEvents() ? $"SELECT xet.target_data " + $"FROM sys.dm_xe_database_session_targets AS xet " + $" INNER JOIN sys.dm_xe_database_sessions AS xe" + - $" ON (xe.address = xet.event_session_address)" + + $" ON (xe.address = xet.event_session_address) " + $"WHERE xe.name = '{SessionName}'" : $"SELECT xet.target_data " + $"FROM sys.dm_xe_session_targets AS xet " + $" INNER JOIN sys.dm_xe_sessions AS xe " + - $" ON (xe.address = xet.event_session_address)" + + $" ON (xe.address = xet.event_session_address) " + $"WHERE xe.name = '{SessionName}'"; using SqlCommand command = new SqlCommand(xEventQuery, _connection); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs index c7fb75ead9..9dd87d8f21 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncCancelledConnectionsTest.cs @@ -1,26 +1,28 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Text; -using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { public class AsyncCancelledConnectionsTest { - private readonly ITestOutputHelper _output; - - private const int NumberOfTasks = 100; // How many attempts to poison the connection pool we will try + /// + /// How many attempts to poison the connection pool we will try. + /// + private const int NumberOfTasks = 100; - private const int NumberOfNonPoisoned = 10; // Number of normal requests for each attempt + /// + /// Number of normal requests for each attempt + /// + private const int NumberOfNonPoisoned = 10; - public AsyncCancelledConnectionsTest(ITestOutputHelper output) - { - _output = output; - } + private bool _continue = true; + private Random _random; // Disabled on Azure since this test fails on concurrent runs on same database. [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] @@ -29,84 +31,53 @@ public AsyncCancelledConnectionsTest(ITestOutputHelper output) public async Task CancelAsyncConnections(bool useMars) { // Arrange - SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString); + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); builder.MultipleActiveResultSets = useMars; - // Act - await RunCancelAsyncConnections(builder); - } - - private async Task RunCancelAsyncConnections(SqlConnectionStringBuilder connectionStringBuilder) - { SqlConnection.ClearAllPools(); - var tracker = new ConcurrentDictionary(); - - _random = new Random(4); // chosen via fair dice roll. - _watch = Stopwatch.StartNew(); + _random = new Random(4); - using (new Timer(TimerCallback, state: null, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5))) + // Act + Task[] tasks = new Task[NumberOfTasks]; + for (int i = 0; i < tasks.Length; i++) { - Task[] tasks = new Task[NumberOfTasks]; - for (int i = 0; i < tasks.Length; i++) - { - tasks[i] = DoManyAsync(i, tracker, connectionStringBuilder); - } - - await Task.WhenAll(tasks); + tasks[i] = DoManyAsync(builder); } - DisplaySummary(); - } + await Task.WhenAll(tasks); - // Display one row every 5'ish seconds - private void TimerCallback(object state) - { - lock (_lockObject) - { - DisplaySummary(); - } - } - - private void DisplaySummary() - { - _output.WriteLine($"{_watch.Elapsed} {_continue} Started:{_start} Done:{_done} InFlight:{_inFlight} RowsRead:{_rowsRead} ResultRead:{_resultRead} PoisonedEnded:{_poisonedEnded} nonPoisonedExceptions:{_nonPoisonedExceptions} PoisonedCleanupExceptions:{_poisonCleanUpExceptions} Found:{_found}"); + // Assert - If test runs to completion, it is successful } - // This is the the main body that our Tasks run - private async Task DoManyAsync(int index, ConcurrentDictionary tracker, SqlConnectionStringBuilder connectionStringBuilder) + // This is the main body that our Tasks run + private async Task DoManyAsync(SqlConnectionStringBuilder connectionStringBuilder) { - Interlocked.Increment(ref _start); - Interlocked.Increment(ref _inFlight); - tracker[index] = true; + string connectionString = connectionStringBuilder.ToString(); - using (SqlConnection marsConnection = new SqlConnection(connectionStringBuilder.ToString())) + using SqlConnection connection = new SqlConnection(connectionString); + if (connectionStringBuilder.MultipleActiveResultSets) { - if (connectionStringBuilder.MultipleActiveResultSets) - { - await marsConnection.OpenAsync(); - } + await connection.OpenAsync(); + } - // First poison - await DoOneAsync(marsConnection, connectionStringBuilder.ToString(), poison: true, index); + // First poison + await DoOneAsync(connection, connectionString, poison: true); - for (int i = 0; i < NumberOfNonPoisoned && _continue; i++) - { - // now run some without poisoning - await DoOneAsync(marsConnection, connectionStringBuilder.ToString(),false,index); - } + for (int i = 0; i < NumberOfNonPoisoned && _continue; i++) + { + // now run some without poisoning + await DoOneAsync(connection, connectionString, poison: false); } - tracker.TryRemove(index, out var _); - Interlocked.Decrement(ref _inFlight); - Interlocked.Increment(ref _done); } - // This will do our work, open a connection, and run a query (that returns 4 results sets) - // if we are poisoning we will - // 1 - Interject some sleeps in the sql statement so that it will run long enough that we can cancel it - // 2 - Setup a time bomb task that will cancel the command a random amount of time later - private async Task DoOneAsync(SqlConnection marsConnection, string connectionString, bool poison, int parent) + private async Task DoOneAsync(SqlConnection marsConnection, string connectionString, bool poison) { + // This will do our work, open a connection, and run a query (that returns 4 results sets) + // if we are poisoning we will + // 1 - Interject some sleeps in the sql statement so that it will run long enough that we can cancel it + // 2 - Set up a time bomb task that will cancel the command a random amount of time later + try { StringBuilder builder = new StringBuilder(); @@ -123,12 +94,12 @@ private async Task DoOneAsync(SqlConnection marsConnection, string connectionStr { if (marsConnection != null && marsConnection.State == System.Data.ConnectionState.Open) { - await RunCommand(marsConnection, builder.ToString(), poison, parent); + await RunCommand(marsConnection, builder.ToString(), poison); } else { await connection.OpenAsync(); - await RunCommand(connection, builder.ToString(), poison, parent); + await RunCommand(connection, builder.ToString(), poison); } } } @@ -138,20 +109,9 @@ private async Task DoOneAsync(SqlConnection marsConnection, string connectionStr } catch (Exception ex) { - if (!poison) - { - Interlocked.Increment(ref _nonPoisonedExceptions); - } - if (ex.Message.Contains("The MARS TDS header contained errors.")) { _continue = false; - lock (_lockObject) - { - _output.WriteLine($"{poison} {DateTime.UtcNow.ToString("O")}"); - _output.WriteLine(ex.ToString()); - } - Interlocked.Increment(ref _found); } throw; @@ -160,126 +120,82 @@ private async Task DoOneAsync(SqlConnection marsConnection, string connectionStr private static bool IsExpectedCancellation(Exception ex) { - if (ex is OperationCanceledException) - { - return true; - } - - if (ex is SqlException sqlEx) + switch (ex) { - return sqlEx.Message.IndexOf("operation cancelled", StringComparison.OrdinalIgnoreCase) >= 0 - || sqlEx.Message.IndexOf("operation canceled", StringComparison.OrdinalIgnoreCase) >= 0; + case OperationCanceledException: + return true; + case SqlException sqlEx: + return sqlEx.Message.Contains("operation cancelled", StringComparison.OrdinalIgnoreCase) || + sqlEx.Message.Contains("operation canceled", StringComparison.OrdinalIgnoreCase); + default: + return false; } - - return false; } - private async Task RunCommand(SqlConnection connection, string commandText, bool poison, int parent) + private async Task RunCommand(SqlConnection connection, string commandText, bool poison) { - int rowsRead = 0; - int resultRead = 0; + using SqlCommand command = connection.CreateCommand(); + command.CommandText = commandText; + Task timeBombTask = null; try { - using (var command = connection.CreateCommand()) + // Set us up the (time) bomb + if (poison) { - Task timeBombTask = default; - try - { - // Setup our time bomb - if (poison) - { - timeBombTask = TimeBombAsync(command); - } - - command.CommandText = commandText; + timeBombTask = TimeBombAsync(command); + } - // Attempt to read all of the data - using (var reader = await command.ExecuteReaderAsync()) + // Attempt to read all the data + using SqlDataReader reader = await command.ExecuteReaderAsync(); + try + { + do + { + while (await reader.ReadAsync() && _continue) { - try - { - do - { - resultRead++; - while (await reader.ReadAsync() && _continue) - { - rowsRead++; - } - } - while (await reader.NextResultAsync() && _continue); - } - catch (SqlException) when (poison) - { - // This looks a little strange, we failed to read above so this should fail too - // But consider the case where this code is elsewhere (in the Dispose method of a class holding this logic) - try - { - while (await reader.NextResultAsync()) - { - } - } - catch - { - Interlocked.Increment(ref _poisonCleanUpExceptions); - } - - throw; - } + // Discard results } } - finally + while (await reader.NextResultAsync() && _continue); + } + catch (SqlException) when (poison) + { + // This looks a little strange, we failed to read above so this should + // fail too. But consider the case where this code is elsewhere (in the + // Dispose method of a class holding this logic) + while (await reader.NextResultAsync()) { - // Make sure to clean up our time bomb - // It is unlikely, but the timebomb may get delayed in the Task Queue - // And we don't want it running after we dispose the command - if (timeBombTask != default) - { - await timeBombTask; - } + // Discard all results } + + throw; } } finally { - Interlocked.Add(ref _rowsRead, rowsRead); - Interlocked.Add(ref _resultRead, resultRead); - if (poison) + // Make sure to clean up our time bomb + // It is unlikely, but the timebomb may get delayed in the task queue, and we don't + // want it running after we dispose the command. + if (timeBombTask != null) { - Interlocked.Increment(ref _poisonedEnded); + await timeBombTask; } } } private async Task TimeBombAsync(SqlCommand command) { - await SleepAsync(100, 3000); - command.Cancel(); - } - - private async Task SleepAsync(int minMs, int maxMs) - { + // Sleep a random amount between 100 and 3000 ms. int delayMs; lock (_random) { - delayMs = _random.Next(minMs, maxMs); + delayMs = _random.Next(100, 3000); } await Task.Delay(delayMs); + + // Cancel the command + command.Cancel(); } - - private Stopwatch _watch; - - private int _inFlight; - private int _start; - private int _done; - private int _rowsRead; - private int _resultRead; - private int _nonPoisonedExceptions; - private int _poisonedEnded; - private int _poisonCleanUpExceptions; - private bool _continue = true; - private int _found; - private Random _random; - private object _lockObject = new object(); } } From 3ec251e9d52b52c16103b6ad435ccba9a53f58c9 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 15 Dec 2025 17:46:59 -0600 Subject: [PATCH 8/8] Make sure files have license headers (and don't have ZWNBSP) --- .../src/Microsoft/Data/SqlClient/ISqlVector.cs | 4 ++++ .../tests/Common/LocalAppContextSwitchesHelper.cs | 4 ++++ .../tests/FunctionalTests/DataCommon/TestUtility.cs | 2 +- .../tests/FunctionalTests/SqlNotificationRequestTest.cs | 6 +++++- .../ManualTests/AlwaysEncrypted/ExceptionsGenericError.cs | 4 ++++ .../AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs | 3 +-- .../AlwaysEncrypted/TestTrustedMasterKeyPaths.cs | 6 +++++- .../tests/ManualTests/DataCommon/XEventScope.cs | 4 ++++ .../AADFedAuthTokenRefreshTest.cs | 2 +- .../SQL/Common/SystemDataInternals/FedAuthTokenHelper.cs | 2 +- .../SQL/ConnectionPoolTest/TransactionPoolTest.cs | 6 +++++- .../tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs | 6 +++++- .../tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs | 6 +++++- .../ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs | 6 +++++- .../tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs | 6 +++++- .../ManualTests/SQL/SqlCommand/SqlCommandStoredProcTest.cs | 2 +- src/Microsoft.Data.SqlClient/tests/UnitTests/ADPHelper.cs | 6 +++++- .../tests/UnitTests/InternalsVisibleToTest.cs | 6 +++++- .../Data/SqlClient/AlwaysEncrypted/NativeAeadBaseline.cs | 6 +++++- .../Microsoft/Data/SqlClient/SqlConnectionStringTest.cs | 6 +++++- .../UnitTests/Microsoft/Data/SqlTypes/SqlVectorTest.cs | 3 +-- 21 files changed, 77 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ISqlVector.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ISqlVector.cs index ca9fe35743..0ecab5ab0f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ISqlVector.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ISqlVector.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + namespace Microsoft.Data.SqlClient { /// diff --git a/src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs b/src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs index 1798e1fcf4..03c61f1881 100644 --- a/src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/Common/LocalAppContextSwitchesHelper.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System; using System.Collections.Generic; using System.Reflection; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/TestUtility.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/TestUtility.cs index 259dc8817a..c4c2ac4d0f 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/TestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/DataCommon/TestUtility.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System; using System.Runtime.InteropServices; namespace Microsoft.Data.SqlClient.Tests diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlNotificationRequestTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlNotificationRequestTest.cs index eb7d204a95..9a32deefdb 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlNotificationRequestTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlNotificationRequestTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using Microsoft.Data.Sql; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionsGenericError.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionsGenericError.cs index b3c51d7fbd..1e3a00931a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionsGenericError.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ExceptionsGenericError.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System; using System.Data; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs index ad9181736f..9929db55d8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/SQLSetupStrategy.cs @@ -1,5 +1,4 @@ - -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information.using System; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestTrustedMasterKeyPaths.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestTrustedMasterKeyPaths.cs index 4012f00914..5a4d3579be 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestTrustedMasterKeyPaths.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestTrustedMasterKeyPaths.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Security.Cryptography.X509Certificates; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs index f87b36aa7a..ce697c9147 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/XEventScope.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System; using System.Data; using System.Threading; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AADFedAuthTokenRefreshTest/AADFedAuthTokenRefreshTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AADFedAuthTokenRefreshTest/AADFedAuthTokenRefreshTest.cs index 027acfde23..54900a4dd0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AADFedAuthTokenRefreshTest/AADFedAuthTokenRefreshTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AADFedAuthTokenRefreshTest/AADFedAuthTokenRefreshTest.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System; using System.Diagnostics; using Microsoft.Data.SqlClient.ManualTesting.Tests.SQL.Common.SystemDataInternals; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/FedAuthTokenHelper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/FedAuthTokenHelper.cs index a0a3bc4498..6e925d1809 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/FedAuthTokenHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Common/SystemDataInternals/FedAuthTokenHelper.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System; using System.Collections; using System.Linq; using System.Reflection; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs index d510b03953..5a6051625d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/TransactionPoolTest.cs @@ -1,4 +1,8 @@ -using System.Transactions; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Transactions; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs index d722ceb4b3..03c5f794c0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonBulkCopyTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Data; using System.IO; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs index 19a0559e1b..f580347f67 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.IO; using System.Data; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs index 21ff771ac0..1176447204 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCompletedTest.cs @@ -1,4 +1,8 @@ -using System.Data; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Data; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs index 7f28a4a09a..b694bc6aee 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandSetTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Data.SqlTypes; using System.Reflection; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandStoredProcTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandStoredProcTest.cs index 211e9c0d38..1c26151d94 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandStoredProcTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandStoredProcTest.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; +using System; using System.Data; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/ADPHelper.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/ADPHelper.cs index d78c36f785..85ad1d7d37 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/ADPHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/ADPHelper.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/InternalsVisibleToTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/InternalsVisibleToTest.cs index eb924990db..b271b0c52e 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/InternalsVisibleToTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/InternalsVisibleToTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using Microsoft.Data.SqlClient.ConnectionPool; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/AlwaysEncrypted/NativeAeadBaseline.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/AlwaysEncrypted/NativeAeadBaseline.cs index 9c5c67de32..945351056f 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/AlwaysEncrypted/NativeAeadBaseline.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/AlwaysEncrypted/NativeAeadBaseline.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlConnectionStringTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlConnectionStringTest.cs index 14bc51d520..eeb6bff3db 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlConnectionStringTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlClient/SqlConnectionStringTest.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using Microsoft.Data.SqlClient.Tests.Common; using Xunit; using static Microsoft.Data.SqlClient.Tests.Common.LocalAppContextSwitchesHelper; diff --git a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlVectorTest.cs b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlVectorTest.cs index 86c0f3ef6c..adca0e2b99 100644 --- a/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlVectorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft/Data/SqlTypes/SqlVectorTest.cs @@ -1,5 +1,4 @@ - -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information.