Skip to content

Conversation

@paulmedynski
Copy link
Contributor

Description

This PR moves all existing MDS tests that use the ActiveDirectoryAuthenticationProvider (ADAP) into the Azure project. The tests are moved as-is with non-functional changes to get them to build/run.

A few MDS tests were unnecessarily using ADAP when they should have been using a test provider, so I updated them to do so.

A full suite of tests for the Azure package will be created in future PRs.

Testing

Existing CI for the Azure and MDS packages should confirm everything.

@paulmedynski paulmedynski added this to the 7.0.0-preview3 milestone Oct 24, 2025
Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary for reviewers.

#pragma warning disable 0618 // Type or member is obsolete
[InlineData(SqlAuthenticationMethod.ActiveDirectoryPassword)]
#pragma warning restore 0618 // Type or member is obsolete
[InlineData(SqlAuthenticationMethod.ActiveDirectoryInteractive)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interactive was missing from the original test, so I added it here.

namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class AADConnectionsTest
public class AADConnectionTest
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test class name didn't match the filename.

// Clear token cache for code coverage.
ActiveDirectoryAuthenticationProvider.ClearUserTokenCache();
using (SqlConnection connection = new SqlConnection(DataTestUtility.AADPasswordConnectionString))
#pragma warning disable 0618 // Type or member is obsolete
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests were unnecessarily using our auth provider, so I updated them to use the test provider defined above, which fetches real tokens via MSAL itself.

@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/move-tests branch from 1903ecc to b17155b Compare October 28, 2025 16:27
@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (feat/azure-split@540c2c6). Learn more about missing BASE report.

Additional details and impacted files
@@                 Coverage Diff                 @@
##             feat/azure-split    #3717   +/-   ##
===================================================
  Coverage                    ?   76.45%           
===================================================
  Files                       ?      271           
  Lines                       ?    43029           
  Branches                    ?        0           
===================================================
  Hits                        ?    32896           
  Misses                      ?    10133           
  Partials                    ?        0           
Flag Coverage Δ
addons 90.82% <ø> (?)
netcore 76.45% <ø> (?)
netfx 75.96% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary for reviewers.

public class AADConnectionsTest
public class AADConnectionTest
{
class CustomSqlAuthenticationProvider : SqlAuthenticationProvider
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to UsernamePasswordProvider.cs so it could be shared.

--verbosity ${{ parameters.verbosity }}
--verbosity ${{ parameters.dotnetVerbosity }}
-p:ReferenceType=${{ parameters.referenceType }}
-p:ForceMdsAssemblyNameSuffix=true
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is explained in my comments on Directory.Build.props.

# to stress test.
- name: pipelineArtifactName
displayName: Pipeline Artifact Name
# The verbosity level for the dotnet CLI commands.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted parameters alphabetically and added some debug/verbosity.

Apply an MDS assembly name suffix, if necessary. See the top-level
Directory.Build.props for more information.
-->
<DefineConstants Condition="'$(ApplyMdsAssemblyNameSuffix)' == 'true'">$(DefineConstants);APPLY_MDS_ASSEMBLY_NAME_SUFFIX</DefineConstants>
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abstractions performs reflection against the MDS assembly, so it needs to know how to form the assembly name. Explained in Directory.Build.props.

Append an assembly name suffix, if necessary. See the top-level
Directory.Build.props for more information.
-->
<AssemblyName>Microsoft.Data.SqlClient</AssemblyName>
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2 ref projects didn't previously specify <AssemblyName>. Not sure why, or if this new addition will cause problems. Thoughts?

<ProjectReference
Condition="'$(TargetGroup)'=='netfx'"
Include="$(NetFxSource)src\Microsoft.Data.SqlClient.csproj" />
<ProjectReference Include="../../../Microsoft.Data.SqlClient.Extensions/Azure/src/Azure.csproj" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures that none of the Functional (or Manual) tests are depending on our auth provider by accident.

//
// TODO: Figure out which ones and install on-demand rather than
// globally.
SqlAuthenticationProvider.SetProvider(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire test suite is now serviced either by this provider, or by the UsernamePasswordProvider on-demand.

No other auth methods have a provider installed.

}
finally
{
if (original is not null)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason there is no unset-provider mechanism, so we're polluting the global scope in the event that no provider was registered before this test.

You will see this pattern elsewhere as well. SetProvider() throws an NRE if you pass null.

<group targetFramework="net462">
<reference file="Microsoft.Data.SqlClient.dll" />
<reference file="Microsoft.Data.SqlClient.xml" />
<reference file="Microsoft.Data.SqlClient$AssemblyNameSuffixNetFx$.dll" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our project-reference based builds probably shouldn't be attempting to generate NuGet packages, but since they do, I made it work. The generated packages aren't used for anything (see CI-SqlClient pipeline), so there is no harm here.

As mentioned in the Directory.Build.props commentary, this is all temporary code anyway and should disappear before 7.0.0 GA.

project to determine whether or not to apply the MDS assembly name suffix.
-->
<ApplyMdsAssemblyNameSuffix>false</ApplyMdsAssemblyNameSuffix>
<ApplyMdsAssemblyNameSuffix
Copy link
Contributor Author

@paulmedynski paulmedynski Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a temporary measure to get the Abstractions and Azure projects (and their tests) to build without having to employ the confusing tricks found in the FunctionalTests, ManualTests, and AKV projects, where we only support building for one type of framework at a time (ick!). This will all disappear when we finally complete the .NET and .NET Framework codebase merge, and we have a single MDS project.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single assembly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed that part since it was confusing. We will produce the same number of MDS assembly files (DLLs), but will no longer be prevented from building them all at once via project references due to multiple projects specifying the same assembly name.

@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/move-tests branch from 5d4f942 to 1e27ff4 Compare November 7, 2025 19:28
@paulmedynski paulmedynski changed the title Move ActiveDirectoryAuthenticationProvider Tests [DRAFT] Move ActiveDirectoryAuthenticationProvider Tests Nov 7, 2025
Base automatically changed from dev/paul/azure-split/authentication to feat/azure-split November 14, 2025 20:08
@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/move-tests branch from 1e27ff4 to 21ab32e Compare November 17, 2025 12:34
Abstractions Package - Pipeline Changes (#3628)
Move AAD/Entra Authentication into new Azure package (#3680)
User Story 39839: Move existing MDS tests to Azure package

- Identified and moved tests specific to ActiveDirectoryAuthenticationProvider into the Azure Test project.
- Updated some MDS tests that unnecessarily used ActiveDirectoryAuthenticationProvider.
- Added tests to Abstractions Test project to ensure AAD/Entra auth fails when the Azure package isn't present.
- Various build and pipeline changes to support the test changes.
- Fixed project-based builds so we can restore MDS netcore and netfx projects at the same time.
- Added caching to the managed identity provider for the ManualTest project.
- Moved username/password Entra auth provider into its own file for sharing across tests.
- Added ADO service connection for test tasks that require access to Azure resources.
- Added workload identity federation tests.
- Solved the mystery of SNI DLLs missing for .NET Framework project-reference-based builds.
- Added ADO-CI-1ES pool jobs to test the Azure package on Linux and Windows.
- Fixed Azure package pipelines to support pools in the ADO.Net and Public projects.
- Added some new pipeline variables to handle the Workload Identity Federation test.
@paulmedynski paulmedynski force-pushed the dev/paul/azure-split/move-tests branch from 21ab32e to 6f7f621 Compare November 17, 2025 17:31
Copy link
Contributor Author

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commentary and things for myself to fix.


namespace Microsoft.Data.SqlClient.Extensions.Azure.Test;

// This class reads configuration information from environment variables and the
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Use XML docs.

// This class reads configuration information from environment variables and the
// config.json file for use by our tests.
//
// Environment variables take precedence over config.json settings.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Note case-sensitivity on non-Windows platforms.


#region Private Methods

private static string GetString(JsonElement element, string name)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Add docs for these helper methods.

// Note that this isn't testing anything in the Azure package. It actually
// tests the static constructor of SqlAuthenticationProviderManager class in
// the MDS package and the static GetProvider() and SetProvider() methods of
// the SqlAuthenticationProvider class in the Abstractions package.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Explain why we're testing this here, and not in MDS or Abstractions tests.

public async void GetCredential()
{
AzurePipelinesCredential credential = new(
// The tenant ID if the managed identity associated to our workload
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski if -> of

Config.UserManagedIdentityClientId,

// The Azure Dev Ops service connection ID (resourceId found in the
// URL) of our workload identity federation setup. See:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Remove "See:"

"printMaxEnumerableLength": 0,
"printMaxStringLength": 0,
"showLiveOutput": false
"_comment": "Options for v3+ are prefixed with '_v3_'",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulmedynski Explain this better.

@paulmedynski paulmedynski changed the title [DRAFT] Move ActiveDirectoryAuthenticationProvider Tests Move ActiveDirectoryAuthenticationProvider Tests Dec 2, 2025
@paulmedynski paulmedynski marked this pull request as ready for review December 2, 2025 11:34
@paulmedynski paulmedynski requested a review from a team as a code owner December 2, 2025 11:34
Copilot AI review requested due to automatic review settings December 2, 2025 11:34
Copilot finished reviewing on behalf of paulmedynski December 2, 2025 11:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates ActiveDirectoryAuthenticationProvider (ADAP) tests from the Microsoft.Data.SqlClient (MDS) test suite to the Azure package. The migration includes infrastructure changes to support project-reference builds with different assembly names for .NET Core and .NET Framework, along with new test utilities and comprehensive pipeline updates.

Key Changes:

  • Build infrastructure updated to handle assembly name suffixes for project-reference builds
  • ActiveDirectoryAuthenticationProvider tests moved from MDS ManualTests to Azure package tests
  • New test provider implementations (UsernamePasswordProvider, ManagedIdentityProvider) added to MDS tests
  • Azure package tests now have comprehensive configuration and pipeline support

Reviewed changes

Copilot reviewed 55 out of 56 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
tools/targets/GenerateMdsPackage.targets Added assembly name suffix properties for project builds
tools/targets/CopySniDllsForNetFxProjectReferenceBuilds.targets New target file to copy SNI DLLs for .NET Framework project builds
tools/specs/Microsoft.Data.SqlClient.nuspec Updated to support optional assembly name suffixes in file paths
src/Microsoft.SqlServer.Server/StringsHelper.cs Added braces for single-line if statements (code style fix)
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs Removed ADAP-dependent tests, added test provider usage for remaining tests
src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/UsernamePasswordProvider.cs New test provider for username/password authentication
src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ManagedIdentityProvider.cs New test provider for managed identity authentication
src/Microsoft.Data.SqlClient/tests/FunctionalTests/AADAuthenticationTests.cs Removed ADAP constructor tests (moved to Azure package)
src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlAuthenticationProviderTest.cs Deleted - tests moved to Azure package
src/Microsoft.Data.SqlClient.Extensions/Azure/test/AADConnectionTest.cs New file with migrated ADAP connection tests
src/Microsoft.Data.SqlClient.Extensions/Azure/test/AADAuthenticationTests.cs New file with migrated ADAP provider constructor tests
src/Microsoft.Data.SqlClient.Extensions/Azure/test/DefaultAuthProviderTests.cs New test verifying ADAP is installed for all AAD methods
src/Microsoft.Data.SqlClient.Extensions/Azure/test/Config.cs New configuration class for Azure package tests
src/Microsoft.Data.SqlClient.Extensions/Abstractions/src/SqlAuthenticationProviderInternal.cs Enhanced to support assembly name suffixes and improved logging
src/Directory.Build.props Added ApplyMdsAssemblyNameSuffix property logic
eng/pipelines/* Multiple pipeline files updated for consistent parameter naming and new test infrastructure

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Comment on lines +64 to +66
arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.buildConfiguration}};ReferenceType=${{parameters.referenceType}};${{parameters.properties}}"'
${{else }}:
arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.buildConfiguration}};ReferenceType=${{parameters.referenceType}};${{parameters.properties}}"'
arguments: 'pack ${{parameters.nuspecPath}} -Version ${{parameters.packageVersion}} -OutputDirectory ${{parameters.outputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.buildConfiguration}};ReferenceType=${{parameters.referenceType}};${{parameters.properties}}"'
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter references have inconsistent casing: ${{parameters.packageVersion}} and ${{parameters.outputDirectory}} use camelCase, but the original code used PascalCase (NugetPackageVersion, OutputDirectory). This change should be verified to ensure the parameters are defined with matching casing in the parameters section of this template file.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +56
throw new TokenException(
$"Failed to acquire token for ManagedIdentity " +
$"userId ={parameters.UserId} error={ex.Message}", ex);
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message in line 55 states "Failed to acquire token for ManagedIdentity" but this is actually a UsernamePasswordProvider. The error message should accurately reflect that this is a username/password authentication failure, not a managed identity failure.

Copilot uses AI. Check for mistakes.
/// A dummy provider that supports all authentication methods.
/// </summary>

// A dummy provider that supports all authentication methods.
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a duplicate comment at line 86-87. Line 83-85 already contains the comment "A dummy provider that supports all authentication methods." The duplicate on line 87 should be removed.

Suggested change
// A dummy provider that supports all authentication methods.

Copilot uses AI. Check for mistakes.
//
internal static class Config
{
# region Config Properties
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the space between '#' and 'region' to follow standard C# preprocessor directive formatting.

Suggested change
# region Config Properties
#region Config Properties

Copilot uses AI. Check for mistakes.

Assert.Throws<SqlException>(() => ConnectAndDisconnect(connStr));

// We cannot verify error message with certainity as driver may cache token from other tests for current user
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct the spelling of "certainty" from "certainity".

Suggested change
// We cannot verify error message with certainity as driver may cache token from other tests for current user
// We cannot verify error message with certainty as driver may cache token from other tests for current user

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +45
await PublicClientApplicationBuilder.Create(_appClientId)
.WithAuthority(parameters.Authority)
.Build()
.AcquireTokenByUsernamePassword(scopes, parameters.UserId, parameters.Password)
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to obsolete method AcquireTokenByUsernamePassword.

Copilot uses AI. Check for mistakes.
}
if (!removeKey)
{
res += key + ";";
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String concatenation in loop: use 'StringBuilder'.

Copilot uses AI. Check for mistakes.
cts.CancelAfter(parameters.ConnectionTimeout * 1000);

string[] scopes = new string[] { scope };
SecureString password = new SecureString();
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to password is useless, since its value is never read.

Copilot uses AI. Check for mistakes.
Comment on lines +362 to +368
if (!string.IsNullOrEmpty(key.Trim()))
{
if (key.Trim().ToLower().StartsWith(keyword.Trim().ToLower(), StringComparison.Ordinal))
{
res = key.Substring(key.IndexOf('=') + 1).Trim();
break;
}
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 'if' statements can be combined.

Suggested change
if (!string.IsNullOrEmpty(key.Trim()))
{
if (key.Trim().ToLower().StartsWith(keyword.Trim().ToLower(), StringComparison.Ordinal))
{
res = key.Substring(key.IndexOf('=') + 1).Trim();
break;
}
if (!string.IsNullOrEmpty(key.Trim()) &&
key.Trim().ToLower().StartsWith(keyword.Trim().ToLower(), StringComparison.Ordinal))
{
res = key.Substring(key.IndexOf('=') + 1).Trim();
break;

Copilot uses AI. Check for mistakes.

internal class UsernamePasswordProvider : SqlAuthenticationProvider
{
string _appClientId;
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field '_appClientId' can be 'readonly'.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants