From 025d4416806a90430b2ae6c8cb56194fc4c342d4 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 18:26:34 -0500 Subject: [PATCH 1/8] Sync config.cs and config.json --- .../Microsoft.Data.SqlClient.TestUtilities/Config.cs | 11 +++++------ .../config.default.json | 7 ++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 6e82dc5076..24c9c4f884 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -15,33 +15,32 @@ public class Config public string TCPConnectionStringHGSVBS = null; public string TCPConnectionStringNoneVBS = null; public string TCPConnectionStringAASSGX = null; + public bool EnclaveEnabled = false; + public bool TracingEnabled = false; public string AADAuthorityURL = null; public string AADPasswordConnectionString = null; public string AADServicePrincipalId = null; public string AADServicePrincipalSecret = null; public string AzureKeyVaultURL = null; public string AzureKeyVaultTenantId = null; + public bool SupportsIntegratedSecurity = false; public string LocalDbAppName = null; public string LocalDbSharedInstanceName = null; - public bool EnclaveEnabled = false; - public bool TracingEnabled = false; - public bool SupportsIntegratedSecurity = false; - public bool ManagedIdentitySupported = true; public string FileStreamDirectory = null; public bool UseManagedSNIOnWindows = false; public string DNSCachingConnString = null; public string DNSCachingServerCR = null; // this is for the control ring public string DNSCachingServerTR = null; // this is for the tenant ring - public bool IsAzureSynapse = false; // True for Azure Data Warehouse/Synapse public bool IsDNSCachingSupportedCR = false; // this is for the control ring public bool IsDNSCachingSupportedTR = false; // this is for the tenant ring public string EnclaveAzureDatabaseConnString = null; + public bool ManagedIdentitySupported = true; public string UserManagedIdentityClientId = null; public string PowerShellPath = null; + public string AliasName = null; public string KerberosDomainPassword = null; public string KerberosDomainUser = null; public bool IsManagedInstance = false; - public string AliasName = null; public static Config Load(string configPath = @"config.json") { diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json index 4362d07c75..df602f11bf 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json @@ -22,7 +22,6 @@ "SupportsIntegratedSecurity": true, "LocalDbAppName": "", "LocalDbSharedInstanceName": "", - "SupportsFileStream": false, "FileStreamDirectory": "", "UseManagedSNIOnWindows": false, "DNSCachingConnString": "", @@ -30,11 +29,13 @@ "DNSCachingServerTR": "", "IsDNSCachingSupportedCR": false, "IsDNSCachingSupportedTR": false, - "IsAzureSynapse": false, "EnclaveAzureDatabaseConnString": "", "ManagedIdentitySupported": true, "UserManagedIdentityClientId": "", "PowerShellPath": "", "AliasName": "", - "WorkloadIdentityFederationServiceConnectionId": "" + "WorkloadIdentityFederationServiceConnectionId": "", + "KerberosDomainPassword": "", + "KerberosDomainuser": "", + "IsManagedInstance": false } From 2d1aa7ed210ba3f4b49d554ee2301221315df27f Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 22:38:40 -0500 Subject: [PATCH 2/8] Move config file to jsonc, make config class nullable --- .gitignore | 1 + .../Config.cs | 117 +++++++++++------- ...rosoft.Data.SqlClient.TestUtilities.csproj | 4 +- ...nfig.default.json => config.default.jsonc} | 0 4 files changed, 73 insertions(+), 49 deletions(-) rename src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/{config.default.json => config.default.jsonc} (100%) diff --git a/.gitignore b/.gitignore index 0d8dfed6d5..ba1a679e48 100644 --- a/.gitignore +++ b/.gitignore @@ -370,6 +370,7 @@ MigrationBackup/ # Config Json file **/config.json +**/config.jsonc # Generated Milestone PR metadata files .milestone-prs/ diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 24c9c4f884..369a58e10f 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -6,69 +6,63 @@ using System.IO; using Newtonsoft.Json; +#nullable enable + namespace Microsoft.Data.SqlClient.TestUtilities { public class Config { - public string TCPConnectionString = null; - public string NPConnectionString = null; - public string TCPConnectionStringHGSVBS = null; - public string TCPConnectionStringNoneVBS = null; - public string TCPConnectionStringAASSGX = null; + public string? TCPConnectionString = null; + public string? NPConnectionString = null; + public string? TCPConnectionStringHGSVBS = null; + public string? TCPConnectionStringNoneVBS = null; + public string? TCPConnectionStringAASSGX = null; public bool EnclaveEnabled = false; public bool TracingEnabled = false; - public string AADAuthorityURL = null; - public string AADPasswordConnectionString = null; - public string AADServicePrincipalId = null; - public string AADServicePrincipalSecret = null; - public string AzureKeyVaultURL = null; - public string AzureKeyVaultTenantId = null; + public string? AADAuthorityURL = null; + public string? AADPasswordConnectionString = null; + public string? AADServicePrincipalId = null; + public string? AADServicePrincipalSecret = null; + public string? AzureKeyVaultURL = null; + public string? AzureKeyVaultTenantId = null; public bool SupportsIntegratedSecurity = false; - public string LocalDbAppName = null; - public string LocalDbSharedInstanceName = null; - public string FileStreamDirectory = null; + public string? LocalDbAppName = null; + public string? LocalDbSharedInstanceName = null; + public string? FileStreamDirectory = null; public bool UseManagedSNIOnWindows = false; - public string DNSCachingConnString = null; - public string DNSCachingServerCR = null; // this is for the control ring - public string DNSCachingServerTR = null; // this is for the tenant ring + public string? DNSCachingConnString = null; + public string? DNSCachingServerCR = null; // this is for the control ring + public string? DNSCachingServerTR = null; // this is for the tenant ring public bool IsDNSCachingSupportedCR = false; // this is for the control ring public bool IsDNSCachingSupportedTR = false; // this is for the tenant ring - public string EnclaveAzureDatabaseConnString = null; + public string? EnclaveAzureDatabaseConnString = null; public bool ManagedIdentitySupported = true; - public string UserManagedIdentityClientId = null; - public string PowerShellPath = null; - public string AliasName = null; - public string KerberosDomainPassword = null; - public string KerberosDomainUser = null; + public string? UserManagedIdentityClientId = null; + public string? PowerShellPath = null; + public string? AliasName = null; + public string? KerberosDomainPassword = null; + public string? KerberosDomainUser = null; public bool IsManagedInstance = false; - public static Config Load(string configPath = @"config.json") + public static Config Load(string configPath) { - // Allow an override of the config path via an environment variable. - configPath = Environment.GetEnvironmentVariable("TEST_MDS_CONFIG") ?? configPath; + Config config = LoadInternal(Environment.GetEnvironmentVariable("TEST_MDS_CONFIG")) ?? + LoadInternal(configPath) ?? + throw new FileNotFoundException("Could not find test configuration file."); - Config config; - try - { - using (StreamReader r = new StreamReader(configPath)) - { - config = JsonConvert.DeserializeObject(r.ReadToEnd()) - ?? throw new InvalidOperationException($"Failed to deserialize config from '{configPath}'."); - } - } - catch - { - throw; - } + // Allow environment variables to override individual config values. + SetFromEnv("MDS_TCPConnectionString", ref config.TCPConnectionString); - static void SetFromEnv(string envVar, ref string configValue) - { - string envValue = Environment.GetEnvironmentVariable(envVar); - if (!string.IsNullOrEmpty(envValue)) - { - configValue = envValue; - } - } + return config; + } + + public static Config Load() + { + // Load config from environment variable first, jsonc file second, json file last. + Config config = LoadInternal(Environment.GetEnvironmentVariable("TEST_MDS_CONFIG")) ?? + LoadInternal("config.jsonc") ?? + LoadInternal("config.json") ?? + throw new FileNotFoundException("Could not find test configuration file."); // Allow environment variables to override individual config values. SetFromEnv("MDS_TCPConnectionString", ref config.TCPConnectionString); @@ -81,5 +75,34 @@ public static void UpdateConfig(Config updatedConfig, string configPath = @"conf string config = JsonConvert.SerializeObject(updatedConfig); File.WriteAllText(configPath, config); } + + private static Config? LoadInternal(string? configPath) + { + if (configPath is null) + { + return null; + } + + try + { + using StreamReader sr = new StreamReader(configPath); + return JsonConvert.DeserializeObject(sr.ReadToEnd()) ?? + throw new InvalidOperationException($"Failed to deserialize config from '{configPath}'"); + } + catch (FileNotFoundException) + { + // File did not exist at the path given. We will try a different location. + return null; + } + } + + private static void SetFromEnv(string envVar, ref string? configValue) + { + string? envValue = Environment.GetEnvironmentVariable(envVar); + if (!string.IsNullOrEmpty(envValue)) + { + configValue = envValue; + } + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj index 083cca8a61..2cb0d4a14a 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj @@ -3,10 +3,10 @@ netstandard2.0 - + - + PreserveNewest diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc similarity index 100% rename from src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json rename to src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc From 0a0830b157c80fa91226086587f4d0419ab9bd21 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 19 May 2026 22:56:49 -0500 Subject: [PATCH 3/8] :robot: updates to other references to config.json --- .github/instructions/testing.instructions.md | 10 +++++----- TESTGUIDE.md | 18 +++++++++--------- .../common/templates/jobs/ci-run-tests-job.yml | 2 +- .../steps/update-config-file-step.yml | 12 ++++++------ eng/pipelines/dotnet-sqlclient-ci-core.yml | 2 +- .../jobs/test-azure-package-ci-job.yml | 2 +- eng/pipelines/kerberos/sqlclient-kerberos.yml | 12 ++++++------ eng/pipelines/stress/stress-tests-job.yml | 6 +++--- .../Azure/test/Config.cs | 16 ++++++++-------- .../SqlDbManager.cs | 6 +++--- .../Config.cs | 2 +- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index 20fe03b1e8..bd9db72c4a 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -14,8 +14,8 @@ src/Microsoft.Data.SqlClient/tests/ ├── UnitTests/ # Unit tests with minimal dependencies └── tools/ └── Microsoft.Data.SqlClient.TestUtilities/ - ├── config.default.json # Template configuration - └── config.json # Local test configuration (git-ignored) + ├── config.default.jsonc # Template configuration + └── config.jsonc # Local test configuration (git-ignored) ``` ## Test Categories @@ -34,14 +34,14 @@ src/Microsoft.Data.SqlClient/tests/ ### Manual Tests (`ManualTests/`) - Full integration tests with SQL Server -- Require `config.json` setup +- Require `config.jsonc` setup - Test real database operations - Include Always Encrypted, Entra ID tests ## Test Configuration -### Setting Up `config.json` -Copy `config.default.json` to `config.json` and configure: +### Setting Up `config.jsonc` +Copy `config.default.jsonc` to `config.jsonc` and configure: ```json { diff --git a/TESTGUIDE.md b/TESTGUIDE.md index aab773a080..1cd85f91b4 100644 --- a/TESTGUIDE.md +++ b/TESTGUIDE.md @@ -195,22 +195,22 @@ conditional tests are skipped. ## Manual Test Configuration Edit the source configuration file at `src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/ -config.json`. The test utilities project copies that file to the test output directory, where the manual tests load it +config.jsonc`. The test utilities project copies that file to the test output directory, where the manual tests load it by default. The template file is: -[src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json](src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json) +[src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc](src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc) -`config.json` is git-ignored. If it does not exist, the test utilities project copies `config.default.json` to -`config.json` before compile. You can also create it manually: +`config.jsonc` is git-ignored. If it does not exist, the test utilities project copies `config.default.jsonc` to +`config.jsonc` before compile. You can also create it manually: ```bash -cp src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json \ - src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.json +cp src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc \ + src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.jsonc ``` -Update `config.json` for your environment before running manual tests. The most important values for a basic run are `TCPConnectionString` and `NPConnectionString`. +Update `config.jsonc` for your environment before running manual tests. The most important values for a basic run are `TCPConnectionString` and `NPConnectionString`. ```jsonc { @@ -233,13 +233,13 @@ For SQL Server in a Linux container, WSL, or another host where SQL authenticati You can override the config file path with the `MDS_TEST_CONFIG` environment variable: ```bash -MDS_TEST_CONFIG=/path/to/config.json dotnet build -t:TestSqlClientManual -p:TestSet=2 +MDS_TEST_CONFIG=/path/to/config.jsonc dotnet build -t:TestSqlClientManual -p:TestSet=2 ``` On PowerShell: ```powershell -$env:MDS_TEST_CONFIG = "C:\path\to\config.json" +$env:MDS_TEST_CONFIG = "C:\path\to\config.jsonc" dotnet build -t:TestSqlClientManual -p:TestSet=2 ``` diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index 5c593e11e3..547213c910 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -217,7 +217,7 @@ jobs: referenceType: Project - ${{ if ne(parameters.configProperties, '{}') }}: - - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml@self # update config.json file + - template: /eng/pipelines/common/templates/steps/update-config-file-step.yml@self # update config.jsonc file parameters: debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml index b10abdc617..8ed6f59ed0 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -151,9 +151,9 @@ steps: Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" displayName: Set Connection String Password - # All properties should be added here, and this template should be used for any manipulation of the config.json file. + # All properties should be added here, and this template should be used for any manipulation of the config.jsonc file. - pwsh: | - $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json + $jdata = Get-Content -Raw "config.default.jsonc" | ConvertFrom-Json foreach ($p in $jdata) { $p.TCPConnectionString="${{parameters.TCPConnectionString }}" @@ -208,13 +208,13 @@ steps: $p.EnclaveEnabled=[System.Convert]::ToBoolean("${{parameters.EnclaveEnabled }}") $p.WorkloadIdentityFederationServiceConnectionId="${{parameters.WorkloadIdentityFederationServiceConnectionId }}" } - $jdata | ConvertTo-Json | Set-Content "config.json" + $jdata | ConvertTo-Json | Set-Content "config.jsonc" workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: 'Update config.json' + displayName: 'Update config.jsonc' - ${{ if eq(parameters.debug, true) }}: - pwsh: | - $jdata = Get-Content -Raw "config.json" | ConvertFrom-Json + $jdata = Get-Content -Raw "config.jsonc" | ConvertFrom-Json foreach ($p in $jdata) { foreach ($prop in $p.PSObject.Properties) @@ -223,4 +223,4 @@ steps: } } workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: '[Debug] Emit config.json' + displayName: '[Debug] Emit config.jsonc' diff --git a/eng/pipelines/dotnet-sqlclient-ci-core.yml b/eng/pipelines/dotnet-sqlclient-ci-core.yml index c8181aff5a..6e29318c90 100644 --- a/eng/pipelines/dotnet-sqlclient-ci-core.yml +++ b/eng/pipelines/dotnet-sqlclient-ci-core.yml @@ -360,7 +360,7 @@ stages: useManagedSNI: ${{parameters.useManagedSNI }} configSqlFor: local operatingSystem: Windows - # config.json properties + # config.jsonc properties configProperties: TCPConnectionString: $(SQL_TCP_CONN_STRING) NPConnectionString: $(SQL_NP_CONN_STRING) diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index cd9b87e103..3f7f6c7cf3 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -227,7 +227,7 @@ jobs: debug: ${{ parameters.debug }} saPassword: ${{ parameters.saPassword }} - # The config.json file has many options, but only some of them are + # The config.jsonc file has many options, but only some of them are # used by the Azure package tests. We only specify the ones that are # necessary here. diff --git a/eng/pipelines/kerberos/sqlclient-kerberos.yml b/eng/pipelines/kerberos/sqlclient-kerberos.yml index eb0016f9fc..9d3eceeb38 100644 --- a/eng/pipelines/kerberos/sqlclient-kerberos.yml +++ b/eng/pipelines/kerberos/sqlclient-kerberos.yml @@ -137,16 +137,16 @@ stages: # requires compile-time parameters. - pwsh: | $managedSni = [System.Convert]::ToBoolean($env:MANAGED_SNI) - $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json + $jdata = Get-Content -Raw "config.default.jsonc" | ConvertFrom-Json foreach ($p in $jdata) { $p.TCPConnectionString = $env:REMOTE_TCP_CONN_STRING $p.NPConnectionString = $env:REMOTE_NP_CONN_STRING $p.SupportsIntegratedSecurity = $true $p.UseManagedSNIOnWindows = $managedSni } - $jdata | ConvertTo-Json | Set-Content "config.json" + $jdata | ConvertTo-Json | Set-Content "config.jsonc" workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: Update test config.json + displayName: Update test config.jsonc env: REMOTE_TCP_CONN_STRING: $(REMOTE_TCP_CONN_STRING) REMOTE_NP_CONN_STRING: $(REMOTE_NP_CONN_STRING) @@ -226,7 +226,7 @@ stages: # --- Update test configuration (with Kerberos credentials) --- - pwsh: | - $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json + $jdata = Get-Content -Raw "config.default.jsonc" | ConvertFrom-Json foreach ($p in $jdata) { $p.TCPConnectionString = $env:REMOTE_TCP_CONN_STRING $p.NPConnectionString = $env:REMOTE_NP_CONN_STRING @@ -234,9 +234,9 @@ stages: } $jdata | Add-Member -NotePropertyName "KerberosDomainUser" -NotePropertyValue $env:KERBEROS_DOMAIN_USER -Force $jdata | Add-Member -NotePropertyName "KerberosDomainPassword" -NotePropertyValue $env:KERBEROS_DOMAIN_PASSWORD -Force - $jdata | ConvertTo-Json | Set-Content "config.json" + $jdata | ConvertTo-Json | Set-Content "config.jsonc" workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities - displayName: Update test config.json (Kerberos) + displayName: Update test config.jsonc (Kerberos) env: REMOTE_TCP_CONN_STRING: $(REMOTE_TCP_CONN_STRING) REMOTE_NP_CONN_STRING: $(REMOTE_NP_CONN_STRING) diff --git a/eng/pipelines/stress/stress-tests-job.yml b/eng/pipelines/stress/stress-tests-job.yml index a216c23864..d7c08dd7bb 100644 --- a/eng/pipelines/stress/stress-tests-job.yml +++ b/eng/pipelines/stress/stress-tests-job.yml @@ -164,7 +164,7 @@ jobs: "@ # Write the JSON content to the config file. - $content | Out-File -FilePath "config.json" + $content | Out-File -FilePath "config.jsonc" # Authenticate with NuGet feeds so that upstream packages (e.g. runtime host packs) can be # fetched through the ADO Artifacts feed. This is required on hosted pool agents (macOS) @@ -208,7 +208,7 @@ jobs: inputs: command: run projects: $(project) - arguments: $(runArguments) --no-build -f ${{ runtime }} -e STRESS_CONFIG_FILE=config.json -- $(testArguments) + arguments: $(runArguments) --no-build -f ${{ runtime }} -e STRESS_CONFIG_FILE=config.jsonc -- $(testArguments) # Run the stress tests for each .NET Framework runtime. - ${{ each runtime in parameters.netFrameworkTestRuntimes }}: @@ -219,4 +219,4 @@ jobs: inputs: command: run projects: $(project) - arguments: $(runArguments) --no-build -f ${{ runtime }} -e STRESS_CONFIG_FILE=config.json -- $(testArguments) + arguments: $(runArguments) --no-build -f ${{ runtime }} -e STRESS_CONFIG_FILE=config.jsonc -- $(testArguments) diff --git a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Config.cs b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Config.cs index f153096d9f..cec4721b95 100644 --- a/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Config.cs +++ b/src/Microsoft.Data.SqlClient.Extensions/Azure/test/Config.cs @@ -10,9 +10,9 @@ namespace Microsoft.Data.SqlClient.Extensions.Azure.Test; /// /// This class reads configuration information from environment variables and -/// the config.json file for use by our tests. +/// the config.jsonc file for use by our tests. /// -/// Environment variables take precedence over config.json settings. Note that +/// Environment variables take precedence over config.jsonc settings. Note that /// variable names are case-sensitive on non-Windows platforms. /// /// The following variables are supported: @@ -30,7 +30,7 @@ namespace Microsoft.Data.SqlClient.Extensions.Azure.Test; /// TEST_MDS_CONFIG: /// The path to the config file to use instead of the default. If not /// supplied, the config file is assumed to be located next to the test -/// assembly and is named config.json. +/// assembly and is named config.jsonc. /// internal static class Config { @@ -86,13 +86,13 @@ internal static bool IsAzureSqlServer() => /// static Config() { - // Read from the config.json file. If the TEST_MDS_CONFIG environment + // Read from the config.jsonc file. If the TEST_MDS_CONFIG environment // variable is set, use it. Otherwise, assume the config file is in the - // working directory and named config.json. + // working directory and named config.jsonc. string configPath = GetEnvVar("TEST_MDS_CONFIG"); if (configPath.IsEmpty()) { - configPath = "config.json"; + configPath = "config.jsonc"; } try @@ -109,10 +109,10 @@ static Config() JsonElement root = doc.RootElement; // See the sample config file for information about these settings: // - // src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json + // src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc // // The sample file is copied to the build output directory as - // config.json by the TestUtilities project file. + // config.jsonc by the TestUtilities project file. // IntegratedSecuritySupported = GetBool(root, "SupportsIntegratedSecurity"); ManagedIdentitySupported = GetBool(root, "ManagedIdentitySupported"); diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs index 52bf5c30f4..6b229d5bc0 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs @@ -19,7 +19,7 @@ public static class SqlDbManager private const string DB_Northwind = "Northwind"; private const string DB_Master = "master"; private const string NorthWindScriptPath = @"../../../../../tools/testsql/createNorthwindDb.sql"; - private const string ConfigPath = @"../Microsoft.Data.SqlClient.TestUtilities/config.json"; + private const string ConfigPath = @"../Microsoft.Data.SqlClient.TestUtilities/config.jsonc"; private const string TCPConnectionString = "TCPConnectionString"; private const string NPConnectionString = "NPConnectionString"; @@ -68,7 +68,7 @@ public static void Run(string[] args) CreateDatabase(dbName, context); Console.WriteLine($"Database [{dbName}] created successfully in {builder.DataSource}"); } - // Update Config.json accordingly + // Update config.jsonc accordingly builder.InitialCatalog = dbName; UpdateConfig(activeConnString.Key, builder); } @@ -96,7 +96,7 @@ public static void Run(string[] args) } if (args[0] == "CreateDatabase") { - // Update config.json with Initial Catalog = for "Active Connection Strings" + // Update config.jsonc with Initial Catalog = for "Active Connection Strings" Config.UpdateConfig(s_configJson, ConfigPath); } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 369a58e10f..ba5f56075e 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -70,7 +70,7 @@ public static Config Load() return config; } - public static void UpdateConfig(Config updatedConfig, string configPath = @"config.json") + public static void UpdateConfig(Config updatedConfig, string configPath = @"config.jsonc") { string config = JsonConvert.SerializeObject(updatedConfig); File.WriteAllText(configPath, config); From ffa9a9bb75a53a6fc30901bfc081988693888f9c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 20 May 2026 12:15:21 -0500 Subject: [PATCH 4/8] Replace newtonsoft with system.text.json --- .../Microsoft.Data.SqlClient.TestUtilities/Config.cs | 6 +++--- .../Microsoft.Data.SqlClient.TestUtilities.csproj | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index ba5f56075e..4ad0acb2f8 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -4,7 +4,7 @@ using System; using System.IO; -using Newtonsoft.Json; +using System.Text.Json; #nullable enable @@ -72,7 +72,7 @@ public static Config Load() public static void UpdateConfig(Config updatedConfig, string configPath = @"config.jsonc") { - string config = JsonConvert.SerializeObject(updatedConfig); + string config = JsonSerializer.Serialize(updatedConfig); File.WriteAllText(configPath, config); } @@ -86,7 +86,7 @@ public static void UpdateConfig(Config updatedConfig, string configPath = @"conf try { using StreamReader sr = new StreamReader(configPath); - return JsonConvert.DeserializeObject(sr.ReadToEnd()) ?? + return JsonSerializer.Deserialize(sr.ReadToEnd()) ?? throw new InvalidOperationException($"Failed to deserialize config from '{configPath}'"); } catch (FileNotFoundException) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj index 2cb0d4a14a..866804844a 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj @@ -2,13 +2,17 @@ netstandard2.0 + + - - PreserveNewest - - + + + + + + From 992fb31572ac24dade8cc12fb2d2a6a3e6cd0894 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 20 May 2026 12:18:59 -0500 Subject: [PATCH 5/8] Allow trailing commas and comments. --- .../Microsoft.Data.SqlClient.TestUtilities/Config.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 4ad0acb2f8..f44e5fe5f8 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -12,6 +12,12 @@ namespace Microsoft.Data.SqlClient.TestUtilities { public class Config { + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + AllowTrailingCommas = true, + ReadCommentHandling = JsonCommentHandling.Skip, + }; + public string? TCPConnectionString = null; public string? NPConnectionString = null; public string? TCPConnectionStringHGSVBS = null; @@ -86,7 +92,7 @@ public static void UpdateConfig(Config updatedConfig, string configPath = @"conf try { using StreamReader sr = new StreamReader(configPath); - return JsonSerializer.Deserialize(sr.ReadToEnd()) ?? + return JsonSerializer.Deserialize(sr.ReadToEnd(), JsonSerializerOptions) ?? throw new InvalidOperationException($"Failed to deserialize config from '{configPath}'"); } catch (FileNotFoundException) From 4474f38d2127f02b3109cde11eb1d6d456c5fbaa Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 20 May 2026 19:08:08 -0500 Subject: [PATCH 6/8] :robot: :hotdog: --- .../common/templates/steps/update-config-file-step.yml | 2 -- .../tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs | 4 +++- .../config.default.jsonc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml index 8ed6f59ed0..1dc9ad22b4 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -188,8 +188,6 @@ steps: $p.DNSCachingConnString="${{parameters.DNSCachingConnString }}" - $p.SupportsFileStream="${{parameters.SupportsFileStream }}" - $p.LocalDbAppName="${{parameters.LocalDbAppName }}" $p.TCPConnectionStringAASSGX="${{parameters.TCPConnectionStringAASSGX }}" diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index f44e5fe5f8..9b438973e1 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -15,6 +15,8 @@ public class Config private static readonly JsonSerializerOptions JsonSerializerOptions = new() { AllowTrailingCommas = true, + IncludeFields = true, + PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, }; @@ -78,7 +80,7 @@ public static Config Load() public static void UpdateConfig(Config updatedConfig, string configPath = @"config.jsonc") { - string config = JsonSerializer.Serialize(updatedConfig); + string config = JsonSerializer.Serialize(updatedConfig, JsonSerializerOptions); File.WriteAllText(configPath, config); } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc index df602f11bf..b2200b03c0 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.jsonc @@ -36,6 +36,6 @@ "AliasName": "", "WorkloadIdentityFederationServiceConnectionId": "", "KerberosDomainPassword": "", - "KerberosDomainuser": "", + "KerberosDomainUser": "", "IsManagedInstance": false } From 57e9b41ca060781df0240e2fc1e7d4b6fd529a17 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Wed, 20 May 2026 18:38:34 -0500 Subject: [PATCH 7/8] Push newtonsoft reference back to manual tests --- .../ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj index 1145fa4790..87652921e4 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTests.csproj @@ -362,6 +362,7 @@ + @@ -389,6 +390,7 @@ + From ef6e8df81c86ebfa7bd6f7a4ee6fb5e7ea3eba66 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 21 May 2026 10:51:31 -0500 Subject: [PATCH 8/8] Remove IsAzureSynapse from pipelines --- eng/pipelines/common/templates/jobs/ci-run-tests-job.yml | 3 --- .../common/templates/steps/update-config-file-step.yml | 5 ----- 2 files changed, 8 deletions(-) diff --git a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml index d6c44271c2..3489bd9abd 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -30,7 +30,6 @@ parameters: # template expansion. # # EnclaveEnabled - # IsAzureSynapse # IsDNSCachingSupportedCR # IsDNSCachingSupportedTR # ManagedIdentitySupported @@ -290,8 +289,6 @@ jobs: IsDNSCachingSupportedCR: ${{ eq(parameters.configProperties.IsDNSCachingSupportedCR, 'true') }} ${{ if parameters.configProperties.IsDNSCachingSupportedTR }}: IsDNSCachingSupportedTR: ${{ eq(parameters.configProperties.IsDNSCachingSupportedTR, 'true') }} - ${{ if parameters.configProperties.IsAzureSynapse }}: - IsAzureSynapse: ${{ eq(parameters.configProperties.IsAzureSynapse, 'true') }} ${{ if parameters.configProperties.ManagedIdentitySupported }}: ManagedIdentitySupported: ${{ eq(parameters.configProperties.ManagedIdentitySupported, 'true') }} diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml index 1dc9ad22b4..30e45d62c4 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -121,10 +121,6 @@ parameters: type: boolean default: false - - name: IsAzureSynapse - type: boolean - default: false - - name: ManagedIdentitySupported type: boolean default: true @@ -199,7 +195,6 @@ steps: $p.UseManagedSNIOnWindows=[System.Convert]::ToBoolean("${{parameters.UseManagedSNIOnWindows }}") $p.SupportsIntegratedSecurity=[System.Convert]::ToBoolean("${{parameters.SupportsIntegratedSecurity }}") $p.ManagedIdentitySupported=[System.Convert]::ToBoolean("${{parameters.ManagedIdentitySupported }}") - $p.IsAzureSynapse=[System.Convert]::ToBoolean("${{parameters.IsAzureSynapse }}") $p.IsDNSCachingSupportedTR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedTR }}") $p.IsDNSCachingSupportedCR=[System.Convert]::ToBoolean("${{parameters.IsDNSCachingSupportedCR }}") $p.TracingEnabled=[System.Convert]::ToBoolean("${{parameters.TracingEnabled }}")