From 109b832038510df5cf076f7f1cb55e5e4c4743f0 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 08:42:45 +0200 Subject: [PATCH 1/6] Test CI with a no-op documentation change Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 82766af84e..6f2d77a3c8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Machine Learning for .NET + + [ML.NET](https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet) is a cross-platform open-source machine learning (ML) framework for .NET. ML.NET allows developers to easily build, train, deploy, and consume custom models in their .NET applications without requiring prior expertise in developing machine learning models or experience with other programming languages like Python or R. The framework provides data loading from files and databases, enables data transformations, and includes many ML algorithms. From a1dea5a0b361cad02a30f65168427fbc9a8b44e6 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 08:44:19 +0200 Subject: [PATCH 2/6] Trigger full CI with a source documentation change Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6dd6e79f-ff2e-4596-ae45-1c842d45bd40 --- src/Microsoft.ML.Data/MLContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.ML.Data/MLContext.cs b/src/Microsoft.ML.Data/MLContext.cs index 4212b8a21f..71ec57aa58 100644 --- a/src/Microsoft.ML.Data/MLContext.cs +++ b/src/Microsoft.ML.Data/MLContext.cs @@ -12,6 +12,7 @@ namespace Microsoft.ML { /// /// Represents the common context for all ML.NET operations. + /// This class is the entry point for creating catalogs and loading data. /// /// /// Once instantiated by the user, this class provides a way to From 0661ba7623c039bb4d89672b25eab8c1155adaeb Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 10:24:57 +0200 Subject: [PATCH 3/6] Use writable copies for LocalDB tests Copy packaged database files to a per-test temporary directory before attaching them so newer LocalDB versions can upgrade the files on Windows CI agents. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6dd6e79f-ff2e-4596-ae45-1c842d45bd40 --- README.md | 2 -- src/Microsoft.ML.Data/MLContext.cs | 1 - test/Microsoft.ML.Tests/DatabaseLoaderTests.cs | 17 +++++++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6f2d77a3c8..82766af84e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Machine Learning for .NET - - [ML.NET](https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet) is a cross-platform open-source machine learning (ML) framework for .NET. ML.NET allows developers to easily build, train, deploy, and consume custom models in their .NET applications without requiring prior expertise in developing machine learning models or experience with other programming languages like Python or R. The framework provides data loading from files and databases, enables data transformations, and includes many ML algorithms. diff --git a/src/Microsoft.ML.Data/MLContext.cs b/src/Microsoft.ML.Data/MLContext.cs index 71ec57aa58..4212b8a21f 100644 --- a/src/Microsoft.ML.Data/MLContext.cs +++ b/src/Microsoft.ML.Data/MLContext.cs @@ -12,7 +12,6 @@ namespace Microsoft.ML { /// /// Represents the common context for all ML.NET operations. - /// This class is the entry point for creating catalogs and loading data. /// /// /// Once instantiated by the user, this class provides a way to diff --git a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs index 2c70e5a9cb..6455f74868 100644 --- a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs +++ b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs @@ -292,8 +292,21 @@ private DatabaseSource GetIrisDatabaseSource(string command, int commandTimeoutI private string GetMSSQLConnectionString(string databaseName) { - var databaseFile = Path.GetFullPath(Path.Combine("TestDatabases", $"{databaseName}.mdf")); - return $@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={databaseFile};Database={databaseName};Integrated Security=True;Connect Timeout=120"; + var sourceDirectory = Path.GetFullPath("TestDatabases"); + var databaseId = Guid.NewGuid().ToString("N"); + var databaseDirectory = Path.Combine(Path.GetTempPath(), "Microsoft.ML.Tests", databaseId); + Directory.CreateDirectory(databaseDirectory); + + // NuGet content files can be read-only on Windows build agents, but LocalDB must upgrade these files. + var databaseFile = Path.Combine(databaseDirectory, $"{databaseName}.mdf"); + File.Copy(Path.Combine(sourceDirectory, $"{databaseName}.mdf"), databaseFile); + File.SetAttributes(databaseFile, FileAttributes.Normal); + + var logFile = Path.Combine(databaseDirectory, $"{databaseName}_log.ldf"); + File.Copy(Path.Combine(sourceDirectory, $"{databaseName}_log.ldf"), logFile); + File.SetAttributes(logFile, FileAttributes.Normal); + + return $@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={databaseFile};Database={databaseName}_{databaseId};Integrated Security=True;Connect Timeout=120"; } private string GetSQLiteConnectionString(string databaseName) From 518ba4df02e40a36456294a3cf376fcecee1038b Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 14:41:09 +0200 Subject: [PATCH 4/6] Clarify LocalDB test setup comment Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- test/Microsoft.ML.Tests/DatabaseLoaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs index 6455f74868..aa6b9079fb 100644 --- a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs +++ b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs @@ -297,7 +297,7 @@ private string GetMSSQLConnectionString(string databaseName) var databaseDirectory = Path.Combine(Path.GetTempPath(), "Microsoft.ML.Tests", databaseId); Directory.CreateDirectory(databaseDirectory); - // NuGet content files can be read-only on Windows build agents, but LocalDB must upgrade these files. + // LocalDB may modify database files when attaching them, so use writable copies of the packaged test data. var databaseFile = Path.Combine(databaseDirectory, $"{databaseName}.mdf"); File.Copy(Path.Combine(sourceDirectory, $"{databaseName}.mdf"), databaseFile); File.SetAttributes(databaseFile, FileAttributes.Normal); From be332d97de8a41e4421d042016517ca41671d1f9 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 15:13:08 +0200 Subject: [PATCH 5/6] Clean up temporary LocalDB test databases Drop each per-test database and remove its temporary files after the test, while logging cleanup failures without masking test results. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6dd6e79f-ff2e-4596-ae45-1c842d45bd40 --- .../Microsoft.ML.Tests/DatabaseLoaderTests.cs | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs index aa6b9079fb..5455ca10da 100644 --- a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs +++ b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs @@ -25,11 +25,67 @@ public class NoParallelizationDefinition { } [Collection(nameof(NoParallelizationDefinition))] public class DatabaseLoaderTests : BaseTestClass { + private string _temporaryDatabaseName; + private string _temporaryDatabaseDirectory; + public DatabaseLoaderTests(ITestOutputHelper output) : base(output) { } + protected override void Cleanup() + { + try + { + if (_temporaryDatabaseName == null) + return; + +#pragma warning disable CS0618 // 'SqlConnection' is obsolete: 'Use the Microsoft.Data.SqlClient package instead.' + SqlConnection.ClearAllPools(); + + using (var connection = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;Database=master;Integrated Security=True;Connect Timeout=120")) + using (var command = connection.CreateCommand()) + { + command.CommandText = $@" +IF DB_ID(@databaseName) IS NOT NULL +BEGIN + ALTER DATABASE [{_temporaryDatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [{_temporaryDatabaseName}]; +END"; + command.Parameters.Add("@databaseName", SqlDbType.NVarChar, 128).Value = _temporaryDatabaseName; + connection.Open(); + command.ExecuteNonQuery(); + } + + SqlConnection.ClearAllPools(); + } + catch (SqlException ex) + { + Output.WriteLine($"Failed to drop temporary LocalDB database '{_temporaryDatabaseName}': {ex}"); + } +#pragma warning restore CS0618 // 'SqlConnection' is obsolete: 'Use the Microsoft.Data.SqlClient package instead.' + finally + { + try + { + if (_temporaryDatabaseDirectory != null && Directory.Exists(_temporaryDatabaseDirectory)) + Directory.Delete(_temporaryDatabaseDirectory, recursive: true); + } + catch (IOException ex) + { + Output.WriteLine($"Failed to delete temporary LocalDB directory '{_temporaryDatabaseDirectory}': {ex}"); + } + catch (UnauthorizedAccessException ex) + { + Output.WriteLine($"Failed to delete temporary LocalDB directory '{_temporaryDatabaseDirectory}': {ex}"); + } + finally + { + base.Cleanup(); + } + } + } + [LightGBMFact] public void IrisLightGbm() { @@ -294,19 +350,20 @@ private string GetMSSQLConnectionString(string databaseName) { var sourceDirectory = Path.GetFullPath("TestDatabases"); var databaseId = Guid.NewGuid().ToString("N"); - var databaseDirectory = Path.Combine(Path.GetTempPath(), "Microsoft.ML.Tests", databaseId); - Directory.CreateDirectory(databaseDirectory); + _temporaryDatabaseName = $"{databaseName}_{databaseId}"; + _temporaryDatabaseDirectory = Path.Combine(Path.GetTempPath(), "Microsoft.ML.Tests", databaseId); + Directory.CreateDirectory(_temporaryDatabaseDirectory); // LocalDB may modify database files when attaching them, so use writable copies of the packaged test data. - var databaseFile = Path.Combine(databaseDirectory, $"{databaseName}.mdf"); + var databaseFile = Path.Combine(_temporaryDatabaseDirectory, $"{databaseName}.mdf"); File.Copy(Path.Combine(sourceDirectory, $"{databaseName}.mdf"), databaseFile); File.SetAttributes(databaseFile, FileAttributes.Normal); - var logFile = Path.Combine(databaseDirectory, $"{databaseName}_log.ldf"); + var logFile = Path.Combine(_temporaryDatabaseDirectory, $"{databaseName}_log.ldf"); File.Copy(Path.Combine(sourceDirectory, $"{databaseName}_log.ldf"), logFile); File.SetAttributes(logFile, FileAttributes.Normal); - return $@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={databaseFile};Database={databaseName}_{databaseId};Integrated Security=True;Connect Timeout=120"; + return $@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename={databaseFile};Database={_temporaryDatabaseName};Integrated Security=True;Connect Timeout=120"; } private string GetSQLiteConnectionString(string databaseName) From 918f387d24dc0eb1b629c3c01c8fb753f4ffe548 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Wed, 12 Aug 2026 18:38:00 +0200 Subject: [PATCH 6/6] Always clear LocalDB connection pools Clear System.Data.SqlClient pools even when dropping a temporary test database fails, while preserving narrow cleanup exception handling. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6dd6e79f-ff2e-4596-ae45-1c842d45bd40 --- .../Microsoft.ML.Tests/DatabaseLoaderTests.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs index 5455ca10da..3291443422 100644 --- a/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs +++ b/test/Microsoft.ML.Tests/DatabaseLoaderTests.cs @@ -43,21 +43,26 @@ protected override void Cleanup() #pragma warning disable CS0618 // 'SqlConnection' is obsolete: 'Use the Microsoft.Data.SqlClient package instead.' SqlConnection.ClearAllPools(); - using (var connection = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;Database=master;Integrated Security=True;Connect Timeout=120")) - using (var command = connection.CreateCommand()) + try { - command.CommandText = $@" + using (var connection = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;Database=master;Integrated Security=True;Connect Timeout=120")) + using (var command = connection.CreateCommand()) + { + command.CommandText = $@" IF DB_ID(@databaseName) IS NOT NULL BEGIN ALTER DATABASE [{_temporaryDatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [{_temporaryDatabaseName}]; END"; - command.Parameters.Add("@databaseName", SqlDbType.NVarChar, 128).Value = _temporaryDatabaseName; - connection.Open(); - command.ExecuteNonQuery(); + command.Parameters.Add("@databaseName", SqlDbType.NVarChar, 128).Value = _temporaryDatabaseName; + connection.Open(); + command.ExecuteNonQuery(); + } + } + finally + { + SqlConnection.ClearAllPools(); } - - SqlConnection.ClearAllPools(); } catch (SqlException ex) {