From c1626772c9ae043bb9c9e64d9a8e2fcb4dffbedc Mon Sep 17 00:00:00 2001 From: Andy Howard Date: Tue, 15 Sep 2026 18:21:09 +0100 Subject: [PATCH] Upgrade Microsoft Data SqlClient --- .../Base/Dbas/DatabaseProvider_Tester.cs | 77 +++++++++++++++++++ SacsStandardDbas/SacsStandardDbas.csproj | 2 +- docs/component-reviews.md | 6 +- docs/topics.md | 1 + eng/README.md | 2 +- 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/SacsCoreUnitTests/Standard/Base/Dbas/DatabaseProvider_Tester.cs b/SacsCoreUnitTests/Standard/Base/Dbas/DatabaseProvider_Tester.cs index 0685449..fce26b7 100644 --- a/SacsCoreUnitTests/Standard/Base/Dbas/DatabaseProvider_Tester.cs +++ b/SacsCoreUnitTests/Standard/Base/Dbas/DatabaseProvider_Tester.cs @@ -69,6 +69,30 @@ namespace Sacs.UnitTests.Net.Standard.Base.Dbas Assert.That(connection.ConnectionString, Is.EqualTo(config.ConnectionString)); } + [Test] + public void OpenOdbcDatabase_CreatesSqlConnectionWithExpectedSecuritySettings() + { + SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig + { + Dbms = DbmsType.MsSql, + Location = "MsSql:db.example.test\\Inventory", + User = "test-user", + Password = "test-password" + }; + + SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config); + using SqlConnection connection = (SqlConnection)database.CreateConnection(); + SqlConnectionStringBuilder settings = new SqlConnectionStringBuilder(connection.ConnectionString); + + Assert.That(settings.DataSource, Is.EqualTo("db.example.test")); + Assert.That(settings.InitialCatalog, Is.EqualTo("Inventory")); + Assert.That(settings.UserID, Is.EqualTo("test-user")); + Assert.That(settings.Password, Is.EqualTo("test-password")); + Assert.That(settings.IntegratedSecurity, Is.False); + Assert.That(settings.Encrypt, Is.EqualTo(SqlConnectionEncryptOption.Mandatory)); + Assert.That(settings.TrustServerCertificate, Is.True); + } + [Test] public void CreateDataAdapter_ReturnsOdbcAdapter() { @@ -194,6 +218,59 @@ namespace Sacs.UnitTests.Net.Standard.Base.Dbas Is.EqualTo(new[] { DbType.Int16, DbType.Int32, DbType.Int64, DbType.Byte, DbType.Single, DbType.Double, DbType.Decimal, DbType.Boolean, DbType.Guid, DbType.DateTime, DbType.Binary })); } + [Test] + public void AddCommandParameter_CreatesSqlValuesWithExpectedTypesAndOrder() + { + ParameterTestItem item = new ParameterTestItem(); + Guid identifier = Guid.Parse("024f2943-12a6-46be-88cf-49980f81e603"); + byte[] data = new byte[] { 1, 2, 3 }; + using SqlCommand command = new SqlCommand(); + + item.AddParameter(command, "@Text", "value"); + item.AddParameter(command, "@Short", (short)12); + item.AddParameter(command, "@Integer", 34); + item.AddParameter(command, "@Long", 56L); + item.AddParameter(command, "@Byte", (byte)78); + item.AddParameter(command, "@Single", 90.1f); + item.AddParameter(command, "@Double", 23.4d); + item.AddParameter(command, "@Decimal", 78.9m); + item.AddParameter(command, "@Boolean", true); + item.AddParameter(command, "@Identifier", identifier); + item.AddParameter(command, "@Data", data); + + Assert.That(command.Parameters.Cast().Select(parameter => parameter.ParameterName), + Is.EqualTo(new[] { "@Text", "@Short", "@Integer", "@Long", "@Byte", "@Single", "@Double", "@Decimal", "@Boolean", "@Identifier", "@Data" })); + Assert.That(command.Parameters.Cast().Select(parameter => parameter.DbType), + Is.EqualTo(new[] { DbType.String, DbType.Int16, DbType.Int32, DbType.Int64, DbType.Byte, DbType.Single, DbType.Double, DbType.Decimal, DbType.Boolean, DbType.Guid, DbType.Binary })); + Assert.That(command.Parameters[0].Value, Is.EqualTo("value")); + Assert.That(command.Parameters[9].Value, Is.EqualTo(identifier)); + Assert.That(command.Parameters[10].Value, Is.SameAs(data)); + } + + [Test] + public void AddCommandParameter_CreatesTypedSqlNulls() + { + ParameterTestItem item = new ParameterTestItem(); + using SqlCommand command = new SqlCommand(); + + item.AddParameter(command, "@Short", null); + item.AddParameter(command, "@Integer", null); + item.AddParameter(command, "@Long", null); + item.AddParameter(command, "@Byte", null); + item.AddParameter(command, "@Single", null); + item.AddParameter(command, "@Double", null); + item.AddParameter(command, "@Decimal", null); + item.AddParameter(command, "@Boolean", null); + item.AddParameter(command, "@Identifier", null); + item.AddParameter(command, "@Date", null); + item.AddParameter(command, "@Data", null); + + Assert.That(command.Parameters.Cast().Select(parameter => parameter.Value), + Is.All.EqualTo(DBNull.Value)); + Assert.That(command.Parameters.Cast().Select(parameter => parameter.DbType), + Is.EqualTo(new[] { DbType.Int16, DbType.Int32, DbType.Int64, DbType.Byte, DbType.Single, DbType.Double, DbType.Decimal, DbType.Boolean, DbType.Guid, DbType.DateTime2, DbType.Binary })); + } + // --- The End --- } } diff --git a/SacsStandardDbas/SacsStandardDbas.csproj b/SacsStandardDbas/SacsStandardDbas.csproj index ba4b155..2a8c267 100644 --- a/SacsStandardDbas/SacsStandardDbas.csproj +++ b/SacsStandardDbas/SacsStandardDbas.csproj @@ -11,7 +11,7 @@ - + diff --git a/docs/component-reviews.md b/docs/component-reviews.md index 7f8ae80..4e8eef4 100644 --- a/docs/component-reviews.md +++ b/docs/component-reviews.md @@ -11,10 +11,10 @@ Last updated: 2026-09-15 | Component | Scope | Status | Date reviewed | Next steps | Notes | |---|---|---|---|---|---| -| `SaCommonVS.sln` | .NET 10 migration build and tests | Migration complete; passing with warnings | 2026-09-15 | Continue the staged package review with the remaining framework-aligned and separately tested major updates. | All supported projects target .NET 10 only. The completed low-risk batch and System.Data.Odbc 10.0.12 pass the complete validation. The solution builds with zero errors and all 141 tests pass; BusinessMgr builds with 11 Control and 13 Portal tests passing. Xamarin remains isolated and unchanged. | +| `SaCommonVS.sln` | .NET 10 migration build and tests | Migration complete; passing with warnings | 2026-09-15 | Continue the staged package review with the remaining framework-aligned and separately tested major updates. | All supported projects target .NET 10 only. The completed low-risk batch, System.Data.Odbc 10.0.12, and Microsoft.Data.SqlClient 7.0.3 pass the complete validation. The solution builds with zero errors and all 144 tests pass; BusinessMgr builds with 11 Control and 13 Portal tests passing. Xamarin remains isolated and unchanged. | | `SacsStandardBase/Base/Utils/ImageUtils.cs` | ImageSharp wrapper | Covered for package upgrades | 2026-09-14 | Extend the suite when adding formats or changing resize policy. | Five in-memory tests cover PNG and JPEG metadata, invalid and truncated input, SVG recognition, format-preserving encoding, proportional landscape and portrait resizing, no-upscale behavior, and invalid constraints. | | `SacsStandardBase` JSON utilities and `SysId` converter | Newtonsoft.Json integration | Covered for package upgrades | 2026-09-14 | Retain the suite for future Newtonsoft.Json updates. | Six tests cover objects, arrays, nulls, serializer settings, valid and invalid parsing paths, dynamic access, `SysId` conversion, independent deep copies, nested collections, and constructor-value replacement. | -| `SacsStandardDbas` provider and parameter creation | Microsoft.Data.SqlClient, System.Data.Odbc, and registry integration | ODBC aligned with .NET 10; broader coverage complete | 2026-09-15 | Add optional configured database integration tests before the planned SqlClient major upgrade. | System.Data.Odbc 10.0.12 is covered by eight database-free tests for provider selection, connection strings, adapter creation, parameter order, scalar and null types, SQL `DateTime2`, ODBC `DateTime`, precision normalization, and sentinel dates. Explicit string, `Int64`, `Decimal`, `Boolean`, and `Guid` mappings correct a defect exposed by the expanded suite. | +| `SacsStandardDbas` provider and parameter creation | Microsoft.Data.SqlClient, System.Data.Odbc, and registry integration | Providers aligned with .NET 10; broader coverage complete | 2026-09-15 | Add optional configured database integration tests when a suitable SQL Server or ODBC test database is available. | Microsoft.Data.SqlClient 7.0.3 and System.Data.Odbc 10.0.12 are covered by eleven database-free tests for provider selection, parsed SQL connection security and authentication settings, adapter creation, parameter order, scalar and null types, SQL `DateTime2`, ODBC `DateTime`, precision normalization, and sentinel dates. The suite explicitly verifies SqlClient 7's mandatory-encryption option. | | `SacsCoreUnitTests` | Test framework, SDK, and coverage tooling | Migrated to NUnit; coverage verified | 2026-09-15 | Use NUnit constraint assertions with `Assert.That` wherever possible. | Uses Microsoft.NET.Test.Sdk 18.10.0, NUnit 4.6.1, NUnit3TestAdapter 6.3.0, NUnit.Analyzers 4.15.0, and coverlet collector 10.0.1. All 126 tests use NUnit's constraint assertion model, pass under NUnit, and produce a non-empty Cobertura report in the optional validation coverage mode. | | `SacsMobileXamarin` | Migration disposition | Isolated; retained for reference | 2026-09-10 | Keep outside the supported build unless a separately scoped resurrection or migration is approved. | Source is unchanged and available through `SaCommonVS.LegacyXamarin.sln`; see `docs/legacy-xamarin.md`. | | [`SacsMobileMaui`](../SacsMobileMaui/docs/component-reviews.md) | Project | .NET 10 migration complete; tracked in project docs | 2026-09-11 | Validate Apple targets on a Mac and continue API cleanup in the project tracker. | The shared project and both active mobile consumers target .NET 10. Windows runtime smoke tests pass, and Windows and Android Debug builds complete with zero errors. | @@ -25,4 +25,4 @@ Last updated: 2026-09-15 | `SacsStandardProc/Proc/Excel/SaMsSpreadsheet_OpenXml.cs` | Class | Dependency upgrade complete; implementation remains incomplete | 2026-09-15 | Scope functional completion and dedicated wrapper tests separately if this implementation is to be revived. | DocumentFormat.OpenXml 3.5.1 builds and passes the existing spreadsheet and downstream validation. The Open XML implementation contains numerous pre-existing unsupported or placeholder operations, so this update does not present it as production-complete. | | `SacsStandardProc/Proc/Excel/SaMsSpreadsheet_POI.cs` | Class | Dependency upgrade complete | 2026-09-12 | Retain the focused spreadsheet suite for future NPOI updates; do not adopt NPOI 2.8.0 without an explicit licensing decision. | NPOI 2.7.6 is paired with an explicit `System.Security.Cryptography.Xml` 10.0.12 reference and NuGet reports no vulnerable packages for `SacsStandardProc`. Nullable date and indexed-colour API changes were adapted. Ten focused tests and all 111 Common tests pass; BusinessMgr builds and its 21 tests pass. | | `SacsStandardBase/Base/Helpers/SacsEncryptionHelper.cs` and `SacsStandardBase/Base/Data/SacsAesIvCrypter.cs` | Classes | Reviewed; action required | 2026-09-08 | Design a versioned authenticated-encryption format with legacy migration and tamper tests. | Current CBC encryption is unauthenticated; password-based key derivation uses a fixed salt and low iteration count. | -| `eng/validate.ps1` | Repository validation | Complete; passing | 2026-09-15 | Use as the standard validation entry point and extend it when repository-wide checks change. | Builds serially, runs the 8-test focused ODBC-provider suite, the 10-test focused NPOI suite, and all 141 Common tests; audits both package-owning projects; verifies changed-file line endings and diffs; then invokes BusinessMgr validation. | +| `eng/validate.ps1` | Repository validation | Complete; passing | 2026-09-15 | Use as the standard validation entry point and extend it when repository-wide checks change. | Builds serially, runs the 11-test focused SQL/ODBC-provider suite, the 10-test focused NPOI suite, and all 144 Common tests; audits both package-owning projects; verifies changed-file line endings and diffs; then invokes BusinessMgr validation. | diff --git a/docs/topics.md b/docs/topics.md index 8a7d64c..83afbb2 100644 --- a/docs/topics.md +++ b/docs/topics.md @@ -44,6 +44,7 @@ Last updated: 2026-09-15 | Topic | Date noted | Date started | Date completed | Outcome | |---|---|---|---|---| +| Upgrade Microsoft.Data.SqlClient and expand SQL provider coverage | 2026-09-15 | 2026-09-15 | 2026-09-15 | Updated Microsoft.Data.SqlClient from 5.2.3 to 7.0.3. Expanded the database-free provider suite from eight to eleven tests, adding parsed SQL connection security and authentication settings plus complete SQL scalar and typed-null parameter coverage. The tests explicitly verify SqlClient 7's mandatory-encryption option. Full Common and downstream BusinessMgr validation passes. | | Align System.Data.Odbc with .NET 10 and expand provider coverage | 2026-09-15 | 2026-09-15 | 2026-09-15 | Updated the Common ODBC dependency from 6.0.2 to 10.0.12 and removed six redundant direct references from BusinessMgr consumers. Expanded the database-free provider suite from four to eight tests, covering non-SQL connections, adapter creation, parameter order, scalar types, and typed nulls. The tests exposed and prompted correction of missing explicit `Int64`, `Decimal`, `Boolean`, `Guid`, and string mappings. All 141 Common tests and both BusinessMgr suites pass. | | Update ZstdNet and cover HTTP decompression | 2026-09-15 | 2026-09-15 | 2026-09-15 | Updated ZstdNet from 1.4.5 to 1.5.7. Added an in-process loopback HTTP test that creates a Zstandard-compressed UTF-8 response and verifies status, headers, native decompression, and decoded content through `SacsHttpClient`. The focused test, all 137 Common tests, and downstream BusinessMgr validation pass. | | Apply the next low-risk Common package updates | 2026-09-15 | 2026-09-15 | 2026-09-15 | Updated MailKit from 4.17.0 to 4.18.0 and DocumentFormat.OpenXml from 3.3.0 to 3.5.1. Replaced the obsolete ASP.NET Core 2.3 `Http` and `StaticFiles` package references with the .NET 10 `Microsoft.AspNetCore.App` shared-framework reference. Added ten content-type regression cases; email, spreadsheet, all 136 Common tests, and downstream BusinessMgr validation pass. | diff --git a/eng/README.md b/eng/README.md index 9ab00f7..2cd6e08 100644 --- a/eng/README.md +++ b/eng/README.md @@ -10,4 +10,4 @@ Use `-SkipRestore` when packages are already restored. Use `-SkipDownstream` onl Use `-CollectCoverage` after changing the test platform or coverage collector. It runs an additional Common coverage pass, validates that a non-empty Cobertura report was produced, and passes the same option to downstream BusinessMgr validation. -The script suppresses .NET first-run setup and banners, builds serially to avoid excessive build-worker creation, runs the focused ODBC-provider and NPOI spreadsheet suites before the complete test project, stores test and optional coverage output under the ignored `TestResults/Validation` folder, audits the ODBC- and NPOI-owning projects for vulnerable packages, checks the Git diff, and verifies working-tree line endings without modifying files. Its isolated `DOTNET_CLI_HOME` stores only CLI state; NuGet packages reuse `NUGET_PACKAGES` when already configured or the user's standard `.nuget/packages` cache. +The script suppresses .NET first-run setup and banners, builds serially to avoid excessive build-worker creation, runs the focused SQL/ODBC-provider and NPOI spreadsheet suites before the complete test project, stores test and optional coverage output under the ignored `TestResults/Validation` folder, audits the database- and NPOI-owning projects for vulnerable packages, checks the Git diff, and verifies working-tree line endings without modifying files. Its isolated `DOTNET_CLI_HOME` stores only CLI state; NuGet packages reuse `NUGET_PACKAGES` when already configured or the user's standard `.nuget/packages` cache.