diff --git a/eng/pipelines/steps/install-dotnet-arm64.ps1 b/eng/pipelines/common/steps/install-dotnet-arm64.ps1 similarity index 100% rename from eng/pipelines/steps/install-dotnet-arm64.ps1 rename to eng/pipelines/common/steps/install-dotnet-arm64.ps1 diff --git a/eng/pipelines/steps/install-dotnet.yml b/eng/pipelines/common/steps/install-dotnet.yml similarity index 97% rename from eng/pipelines/steps/install-dotnet.yml rename to eng/pipelines/common/steps/install-dotnet.yml index 5774984663..6ce99316b2 100644 --- a/eng/pipelines/steps/install-dotnet.yml +++ b/eng/pipelines/common/steps/install-dotnet.yml @@ -69,6 +69,7 @@ steps: env: PROCESSOR_ARCHITECTURE: x86 + # Install the desired Runtimes, if any. - ${{ each version in parameters.runtimes }}: - task: UseDotNet@2 @@ -96,7 +97,7 @@ steps: inputs: targetType: filePath pwsh: true - filePath: $(Build.SourcesDirectory)/eng/pipelines/steps/install-dotnet-arm64.ps1 + filePath: $(Build.SourcesDirectory)/eng/pipelines/common/steps/install-dotnet-arm64.ps1 # Arguments: # # -Debug: diff --git a/eng/pipelines/steps/restore-dotnet-tools.yml b/eng/pipelines/common/steps/restore-dotnet-tools.yml similarity index 100% rename from eng/pipelines/steps/restore-dotnet-tools.yml rename to eng/pipelines/common/steps/restore-dotnet-tools.yml diff --git a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml index de9b4d284f..aa6a1c50c5 100644 --- a/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-build-nugets-job.yml @@ -132,10 +132,10 @@ jobs: targetPath: $(localFeedPath) # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # When we're performing a Debug build, we still want to try _compiling_ the # code in Release mode to ensure downstream pipelines don't encounter diff --git a/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml b/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml index 09c72e9719..95c0ac0f3c 100644 --- a/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-code-coverage-job.yml @@ -44,7 +44,7 @@ jobs: displayName: '[Debug] List Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} 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 4c42af8dc1..5eed840236 100644 --- a/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml +++ b/eng/pipelines/common/templates/jobs/ci-run-tests-job.yml @@ -30,11 +30,9 @@ parameters: # template expansion. # # EnclaveEnabled - # IsAzureSynapse # IsDNSCachingSupportedCR # IsDNSCachingSupportedTR # ManagedIdentitySupported - # SupportsFileStream # SupportsIntegratedSecurity # TracingEnabled # @@ -211,7 +209,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} ${{ if parameters.isArm64 }}: @@ -223,7 +221,7 @@ jobs: runtimes: [8.x, 9.x] # Restore dotnet CLI tools (e.g. pwsh, apicompat) before building. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self - ${{ if ne(parameters.prebuildSteps, '') }}: - ${{ parameters.prebuildSteps }} # extra steps to run before the build like downloading sni and the required configuration @@ -279,8 +277,6 @@ jobs: AliasName: ${{ parameters.configProperties.AliasName }} ${{ if parameters.configProperties.SupportsIntegratedSecurity }}: SupportsIntegratedSecurity: ${{ eq(parameters.configProperties.SupportsIntegratedSecurity, 'true') }} - ${{ if parameters.configProperties.SupportsFileStream }}: - SupportsFileStream: ${{ eq(parameters.configProperties.SupportsFileStream, 'true') }} ${{ if parameters.configProperties.DNSCachingConnString }}: DNSCachingConnString: ${{ parameters.configProperties.DNSCachingConnString }} ${{ if parameters.configProperties.DNSCachingServerCR }}: @@ -293,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') }} @@ -352,7 +346,7 @@ jobs: - ${{ if and(eq(parameters.enableX86Test, true), eq(parameters.operatingSystem, 'Windows')) }}: - ${{ if ne(variables['dotnetx86RootPath'], '') }}: # Install the .NET SDK and Runtimes for x86. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: architecture: x86 debug: ${{ parameters.debug }} diff --git a/eng/pipelines/common/templates/steps/pre-build-step.yml b/eng/pipelines/common/templates/steps/pre-build-step.yml index 068223af70..1d57d18296 100644 --- a/eng/pipelines/common/templates/steps/pre-build-step.yml +++ b/eng/pipelines/common/templates/steps/pre-build-step.yml @@ -5,7 +5,7 @@ ################################################################################# steps: # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] 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..b0612fa248 100644 --- a/eng/pipelines/common/templates/steps/update-config-file-step.yml +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -93,10 +93,6 @@ parameters: type: boolean default: false - - name: SupportsFileStream - type: boolean - default: false - - name: DNSCachingConnString type: string default: '' @@ -121,10 +117,6 @@ parameters: type: boolean default: false - - name: IsAzureSynapse - type: boolean - default: false - - name: ManagedIdentitySupported type: boolean default: true @@ -188,8 +180,6 @@ steps: $p.DNSCachingConnString="${{parameters.DNSCachingConnString }}" - $p.SupportsFileStream="${{parameters.SupportsFileStream }}" - $p.LocalDbAppName="${{parameters.LocalDbAppName }}" $p.TCPConnectionStringAASSGX="${{parameters.TCPConnectionStringAASSGX }}" @@ -201,7 +191,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 }}") diff --git a/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml b/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml index 6c74c01988..604f1b7894 100644 --- a/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml +++ b/eng/pipelines/common/templates/steps/verify-nuget-package-step.yml @@ -34,7 +34,7 @@ parameters: steps: # Install the .NET SDK, required by the PowerShell script. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Invoke the script with the path to the packages to verify. - task: PowerShell@2 diff --git a/eng/pipelines/onebranch/variables/common-variables.yml b/eng/pipelines/common/variables/common-variables.yml similarity index 54% rename from eng/pipelines/onebranch/variables/common-variables.yml rename to eng/pipelines/common/variables/common-variables.yml index 5b6209d59d..5f4532778d 100644 --- a/eng/pipelines/onebranch/variables/common-variables.yml +++ b/eng/pipelines/common/variables/common-variables.yml @@ -4,11 +4,9 @@ # See the LICENSE file in the project root for more information. # ################################################################################# -# Common variables shared across all OneBranch Official pipelines. +# Common variables shared across all pipelines. variables: - - name: CommitHead - value: '' # the value will be extracted from the repo's head ########################################################################## # "Well-Known" Variables that are ok to use directly, anywhere in the pipeline. @@ -21,15 +19,3 @@ variables: # ). - name: BUILD_OUTPUT value: $(REPO_ROOT)/artifacts - - # Directory where downloaded pipeline artifacts (NuGet packages from earlier - # stages) are placed. Build jobs use this as a local NuGet package source so - # that downstream packages can resolve dependencies on packages built by - # upstream stages. - - name: JOB_INPUT - value: $(REPO_ROOT)/packages - - # Root directory for all job output artifacts (NuGet packages, symbols, etc.). OneBranch auto - # publishes everything under this directory as the artifact for the job. - - name: JOB_OUTPUT - value: $(REPO_ROOT)/output diff --git a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml index aed7672618..a9cb5b1043 100644 --- a/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-abstractions-package-ci-job.yml @@ -103,7 +103,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-azure-package-ci-job.yml b/eng/pipelines/jobs/pack-azure-package-ci-job.yml index 3b03dc0adc..eaf0e3c66f 100644 --- a/eng/pipelines/jobs/pack-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-azure-package-ci-job.yml @@ -146,7 +146,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-logging-package-ci-job.yml b/eng/pipelines/jobs/pack-logging-package-ci-job.yml index dd748cb4b2..f2a42699e0 100644 --- a/eng/pipelines/jobs/pack-logging-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-logging-package-ci-job.yml @@ -94,7 +94,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml b/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml index 915bf1e9bd..6b19e8c154 100644 --- a/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml +++ b/eng/pipelines/jobs/pack-sqlserver-package-ci-job.yml @@ -90,7 +90,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} diff --git a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml index 226dc1ae2a..83366b52a9 100644 --- a/eng/pipelines/jobs/test-abstractions-package-ci-job.yml +++ b/eng/pipelines/jobs/test-abstractions-package-ci-job.yml @@ -122,7 +122,7 @@ jobs: displayName: '[Debug] Print Environment Variables' # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} runtimes: [8.x, 9.x] diff --git a/eng/pipelines/jobs/test-azure-package-ci-job.yml b/eng/pipelines/jobs/test-azure-package-ci-job.yml index 9c70433e33..42097daa42 100644 --- a/eng/pipelines/jobs/test-azure-package-ci-job.yml +++ b/eng/pipelines/jobs/test-azure-package-ci-job.yml @@ -243,7 +243,7 @@ jobs: targetPath: $(Build.SourcesDirectory)/packages # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: debug: ${{ parameters.debug }} runtimes: [8.x, 9.x] diff --git a/eng/pipelines/kerberos/sqlclient-kerberos.yml b/eng/pipelines/kerberos/sqlclient-kerberos.yml index af1b04266f..f43ee0a280 100644 --- a/eng/pipelines/kerberos/sqlclient-kerberos.yml +++ b/eng/pipelines/kerberos/sqlclient-kerberos.yml @@ -127,13 +127,13 @@ stages: fetchDepth: 1 fetchTags: false - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during the SqlClient ref project build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # --- Update test configuration --- # Uses runtime variables from the matrix ($(managedSNI)) so we use @@ -224,13 +224,13 @@ stages: fetchTags: false # --- Install .NET SDK and runtimes --- - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during the SqlClient ref project build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # --- Update test configuration (with Kerberos credentials) --- - pwsh: | diff --git a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml index 34c775ad5c..51c70e8c64 100644 --- a/eng/pipelines/onebranch/jobs/build-buildproj-job.yml +++ b/eng/pipelines/onebranch/jobs/build-buildproj-job.yml @@ -128,11 +128,11 @@ jobs: targetPath: $(REPO_ROOT)/packages # Install the .NET SDK. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self # Restore dotnet local tools (pwsh, apicompat, etc.). Required by build.proj targets # such as _CheckPwshToolRestored that run during RoslynAnalyzers and Build. - - template: /eng/pipelines/steps/restore-dotnet-tools.yml@self + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self # Perform Roslyn analysis before building, since this step will clobber build output. - template: /eng/pipelines/onebranch/steps/roslyn-analyzers-buildproj-step.yml@self diff --git a/eng/pipelines/onebranch/sqlclient-non-official.yml b/eng/pipelines/onebranch/sqlclient-non-official.yml index 584bd050f9..abf9b6dcbe 100644 --- a/eng/pipelines/onebranch/sqlclient-non-official.yml +++ b/eng/pipelines/onebranch/sqlclient-non-official.yml @@ -90,7 +90,7 @@ parameters: default: false variables: - - template: /eng/pipelines/onebranch/variables/common-variables.yml@self + - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/onebranch/variables/onebranch-variables.yml@self - template: /eng/pipelines/onebranch/variables/package-variables.yml@self parameters: diff --git a/eng/pipelines/onebranch/sqlclient-official.yml b/eng/pipelines/onebranch/sqlclient-official.yml index 07b8da1b17..8ea429bb00 100644 --- a/eng/pipelines/onebranch/sqlclient-official.yml +++ b/eng/pipelines/onebranch/sqlclient-official.yml @@ -112,7 +112,7 @@ parameters: default: false variables: - - template: /eng/pipelines/onebranch/variables/common-variables.yml@self + - template: /eng/pipelines/common/variables/common-variables.yml@self - template: /eng/pipelines/onebranch/variables/onebranch-variables.yml@self - template: /eng/pipelines/onebranch/variables/package-variables.yml@self parameters: diff --git a/eng/pipelines/onebranch/steps/build-buildproj-step.yml b/eng/pipelines/onebranch/steps/build-buildproj-step.yml index 080896ee10..2a5730c848 100644 --- a/eng/pipelines/onebranch/steps/build-buildproj-step.yml +++ b/eng/pipelines/onebranch/steps/build-buildproj-step.yml @@ -6,6 +6,10 @@ # This collection of steps to build a project via the build.proj. This will execute the "Build*" # target in build.proj, where * is the packageShortName provided in the parameters. +# +# Note: This differs from the pr/ci build-buildproj-step.yml in that it always strong-name signs +# the assemblies, it only builds in package reference mode, and as such allows for version +# parameters to be provided. parameters: # Build configuration - Release or Debug. diff --git a/eng/pipelines/onebranch/variables/onebranch-variables.yml b/eng/pipelines/onebranch/variables/onebranch-variables.yml index 5a36dbbe75..7d940c1cb7 100644 --- a/eng/pipelines/onebranch/variables/onebranch-variables.yml +++ b/eng/pipelines/onebranch/variables/onebranch-variables.yml @@ -32,8 +32,25 @@ variables: # SymbolsUploadAccount - group: 'symbols-variables-v3' + # Well-Known Variables ################################################### + + # Directory where downloaded pipeline artifacts (NuGet packages from earlier + # stages) are placed. Build jobs use this as a local NuGet package source so + # that downstream packages can resolve dependencies on packages built by + # upstream stages. + - name: JOB_INPUT + value: $(REPO_ROOT)/packages + + # Root directory for all job output artifacts (NuGet packages, symbols, etc.). OneBranch auto + # publishes everything under this directory as the artifact for the job. + - name: JOB_OUTPUT + value: $(REPO_ROOT)/output + # OneBranch Template Variables ########################################### + - name: CommitHead + value: '' # the value will be extracted from the repo's head + # https://aka.ms/obpipelines/sdl - name: ob_sdl_binskim_break value: true @@ -42,7 +59,7 @@ variables: value: true # OneBranch supplies a variety of container images we must use for our jobs. - # + # Windows jobs use this image. - name: WindowsContainerImage value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest diff --git a/eng/pipelines/pr/jobs/test-buildproj-job.yml b/eng/pipelines/pr/jobs/test-buildproj-job.yml new file mode 100644 index 0000000000..0b051bf50e --- /dev/null +++ b/eng/pipelines/pr/jobs/test-buildproj-job.yml @@ -0,0 +1,89 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # General Parameters ===================================================== + + # Configuration with which to build the packages and execute the tests. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to append to the package version to indicate it is a pre-release/development build. + - name: buildSuffix + type: string + + # Platform Parameters ==================================================== + + # Display name of the platform. This will be formatted into the job's official name as well as + # the display name for the job. As such, only alphanumeric and _ characters are permitted. + - name: platformDisplayName + type: string + + # TFM name of the version of dotnet to run this test with. + - name: platformDotnet + type: string + + # Name of the image in the customized ADO pool to use to execute this job. + - name: platformImage + type: string + + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + + # Test Parameters ======================================================== + + # Name of the project to run tests for. This will be used to generate the build.proj target to + # execute: Test{packageShortName}{testProject} + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + + # Display name of the test target that is being executed. This will be formatted into the job's + # official name as well as the display name for the job. As such, only alphanumeric and _ + # characters are permitted. + - name: testDisplayName + type: string + + # Optional test project name to execute. This only applies to packages that have >1 test target. + # eg, for TestSqlClientManual, this should be "Manual" + - name: testProject + type: string + default: '' + +jobs: + - job: "test_${{ parameters.platformDisplayName }}_${{ parameters.testDisplayName }}" + displayName: "${{ parameters.testDisplayName }}_${{ parameters.platformDisplayName }}" + + pool: + name: ${{ parameters.poolName }} + demands: + - imageOverride -equals ${{ parameters.platformImage }} + + steps: + # Install the version of the dotnet runtime we will use to execute the test target. + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self + parameters: + runtimeVersion: ${{ parameters.platformDotnet }} + + # Execute the test target + - template: /eng/pipelines/pr/steps/test-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + + packageShortName: ${{ parameters.packageShortName }} + testFramework: ${{ parameters.platformDotnet }} + testProject: ${{ parameters.testProject }} diff --git a/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml new file mode 100644 index 0000000000..ff81d983a3 --- /dev/null +++ b/eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml @@ -0,0 +1,160 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # Configuration with which to build the packages and execute the tests. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to append to the package version to indicate it is a pre-release/development build. + - name: buildSuffix + type: string + + # Name of the stage that generated the SA password + - name: stageNameSecrets + type: string + + # Platform Parameters ==================================================== + + # Display name of the platform. This will be formatted into the job's official name as well as + # the display name for the job. As such, only alphanumeric and _ characters are permitted. + - name: platformDisplayName + type: string + + # TFM name of the version of dotnet to run this test with. + - name: platformDotnet + type: string + + # Name of the image in the customized ADO pool to use to execute this job. + - name: platformImage + type: string + + # General name of the operating system that will be used to execute the job. + # Note: This is used at compile time to determine which SQL Server setup steps to use. As such, + # this cannot be replaced with the agent's operating system, as this value is only available + # at runtime. + - name: platformOperatingSystem + type: string + values: + - Windows + - Linux + + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + + # Test Configuration Parameters ========================================== + + # Azure Key Vault tenant ID that will be set in the config.json file. + - name: azureKeyVaultTenantId + type: string + + # Azure Key Vault URL that will be set in the config.json file. + - name: azureKeyVaultUrl + type: string + + # Connection string using named pipes that will be set in the config.json file. + - name: connectionStringNp + type: string + + # Connection string using TCP that will be set in the config.json file. + - name: connectionStringTcp + type: string + + # Path to use for file stream tests, this value will be stored in the config.json file. + - name: fileStreamDirectory + type: string + + # Name of the local DB application name for localdb tests, this value will be stored in the + # config.json + - name: localDbAppName + type: string + + # Name of the local DB shared instance name for localdb tests, this value will be stored in the + # config.json + - name: localDbSharedInstanceName + type: string + +jobs: + - job: "test_${{ parameters.platformDisplayName }}_sqlclient_manual" + displayName: "sqlclient_manual_${{ parameters.platformDisplayName }}" + + pool: + name: ${{ parameters.poolName }} + demands: + - imageOverride -equals ${{ parameters.platformImage }} + + variables: + # Bring the generated SA password from the secrets stage into scope for this test stage. + # Note: Because this is set at runtime, it must be referenced as `$(saPassword)`. + - name: saPassword + value: $[stageDependencies.${{ parameters.stageNameSecrets }}.secrets_job.outputs['SaPassword.Value']] + + steps: + # Install the version of the dotnet runtime we will use to execute the test target. + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self + parameters: + runtimeVersion: ${{ parameters.platformDotnet }} + + # Configure the local SQL Server instance + - template: /eng/pipelines/pr/steps/configure-sqlserver-step.yml@self + parameters: + fileStreamDirectory: ${{ parameters.fileStreamDirectory }} + operatingSystem: ${{ parameters.platformOperatingSystem }} + saPassword: $(saPassword) + + # Assign the generated SA password to the $Password field. This will allow $(Password) to be + # be replaced in connection strings with whatever set in the secrets stage. + - pwsh: | + $password = "$(saPassword)" + Write-Host "##vso[task.setvariable variable=Password;isSecret=true]$password" + displayName: Set Connection String Password + + # Write configuration information to the config.json file. + - pwsh: | + # Read existing default configuration from file + $defaultConfigPath = "$(REPO_ROOT)/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json" + $configDirectory = "$(Agent.TempDirectory)/mds-config" + $configPath = Join-Path $configDirectory "config.json" + $config = Get-Content -Raw $defaultConfigPath | ConvertFrom-Json + + # Update the config values + $config.TCPConnectionString = "${{ parameters.connectionStringTcp }}" + $config.NPConnectionString = "${{ parameters.connectionStringNp }}" + $config.AzureKeyVaultURL = "${{ parameters.azureKeyVaultUrl }}" + $config.AzureKeyVaultTenantId = "${{ parameters.azureKeyVaultTenantId }}" + $config.LocalDbAppName = "${{ parameters.localDbAppName }}" + $config.LocalDbSharedInstanceName = "${{ parameters.localDbSharedInstanceName }}" + $config.ManagedIdentitySupported = $true + $config.SupportsIntegratedSecurity = $false + + if ("${{ parameters.platformOperatingSystem }}" -eq "Windows") { + $config.FileStreamDirectory = "${{ parameters.fileStreamDirectory }}" + } else { + $config.FileStreamDirectory = "" + } + + # Write config object to config file + New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null + $config | ConvertTo-Json | Set-Content $configPath + + # Set generated config file path to environment variable + Write-Host "##vso[task.setvariable variable=TEST_MDS_CONFIG]$configPath" + displayName: 'Generate manual test config' + + # Execute TestSqlClientManual target from build.proj + - template: /eng/pipelines/pr/steps/test-buildproj-step.yml + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + + packageShortName: "SqlClient" + testFramework: ${{ parameters.platformDotnet }} + testProject: "Manual" + diff --git a/eng/pipelines/pr/pr-pipeline.yml b/eng/pipelines/pr/pr-pipeline.yml new file mode 100644 index 0000000000..9774ebdbfa --- /dev/null +++ b/eng/pipelines/pr/pr-pipeline.yml @@ -0,0 +1,77 @@ +################################################################################# +# 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. # +################################################################################# + +name: $(DayOfYear)$(Rev:rr) + +variables: + - template: /eng/pipelines/common/variables/common-variables.yml@self + - template: /eng/pipelines/pr/variables/pr-variables.yml@self + +stages: + # Stage 1a: Build and pack all projects in the repository + - template: /eng/pipelines/pr/stages/pack-stage.yml + parameters: + buildConfiguration: Debug + buildSuffix: pr + stageName: ${{ variables.stageNamePack }} + + # Stage 1b: Generate secrets + - template: /eng/pipelines/pr/stages/generate-secrets-stage.yml + parameters: + stageName: ${{ variables.stageNameSecrets }} + + # Stage 2: Execute tests and collect code coverage + - template: /eng/pipelines/pr/stages/test-stages.yml + parameters: + buildConfiguration: Debug + buildSuffix: pr + poolName: $(PoolNameDefault) + stageNamePack: ${{ variables.stageNamePack }} + stageNameSecrets: ${{ variables.stageNameSecrets }} + + platforms: + - displayName: "windows_net462" + dotnet: "net462" + image: "ADO-MMS22-SQL22" + operatingSystem: "Windows" + - displayName: "windows_net8" + dotnet: "net8.0" + image: "ADO-MMS22-SQL22" + operatingSystem: "Windows" + - displayName: "windows_net9" + dotnet: "net9.0" + image: "ADO-MMS22-SQL22" + operatingSystem: "Windows" + - displayName: "windows_net10" + dotnet: "net10.0" + image: "ADO-MMS22-SQL22" + operatingSystem: "Windows" + + - displayName: "linux_net8" + dotnet: "net8.0" + image: "ADO-UB22-SQL22" + operatingSystem: "Linux" + - displayName: "linux_net9" + dotnet: "net9.0" + image: "ADO-UB22-SQL22" + operatingSystem: "Linux" + - displayName: "linux_net10" + dotnet: "net10.0" + image: "ADO-UB22-SQL22" + operatingSystem: "Linux" + + manualTestAzureKeyVaultUrl: $(AzureKeyVaultUrl) + manualTestAzureKeyVaultTenantId: $(AzureKeyVaultTenantId) + manualTestConnectionStringNpLocalhost: $(ConnectionStringNp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringTcpLocalhost: $(ConnectionStringTcp_LocalhostDefault_UsernamePassword) + manualTestConnectionStringNpAzure: $(ConnectionStringNp_Azure_ManagedIdentity) + manualTestConnectionStringTcpAzure: $(ConnectionStringTcp_Azure_ManagedIdentity) + manualTestFileStreamDirectory: "$(Pipeline.Workspace)/filestream" + manualTestLocalDbAppName: $(LocalDbAppName) + manualTestLocalDbSharedInstanceName: $(LocalDbSharedInstanceName) + + # Stage 3: Collect code coverage + # @TODO: diff --git a/eng/pipelines/pr/stages/generate-secrets-stage.yml b/eng/pipelines/pr/stages/generate-secrets-stage.yml new file mode 100644 index 0000000000..20a81fe626 --- /dev/null +++ b/eng/pipelines/pr/stages/generate-secrets-stage.yml @@ -0,0 +1,69 @@ +#################################################################################################### +# 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. +#################################################################################################### + +# This stage generates the following random secrets for use throughout the PR and CI pipelines: +# SaPassword - A random GUID suitable for use as the SA password of local SQL Server instances. +# +# Subsequent stages may reference these variables as: +# $[stageDependencies.${{ stageName }}.secrets_job.outputs['SaPassword.Value']] +# +# For further details on the stage-dependency syntax, see: +# https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash#set-an-output-variable-for-use-in-future-stages +# +# Any stages that use these secrets must depend on this stage: +# ${{ stageName }} +# +# None of the values produced here are actual secrets - they are just random values that are +# suitable for testing purposes, and do not need to be protected. For simplicity, they are emitted +# as regular output variables of script steps, are not formally marked as secrets, and not stored in +# the Azure DevOps Library or Key Vault. + +parameters: + + # True to emit debug information and steps. + - name: debug + type: boolean + default: false + + - name: stageName + type: string + +stages: + + # The stage downstream stages must depend on to ensure the secrets are generated before they are + # used. + - stage: ${{ parameters.stageName }} + displayName: Generate Secrets + dependsOn: [] + + jobs: + + # The job that generates the secrets. Each secret is emitted as an output variable of a + # script step and can be referenced by downstream stages via the stage-dependencies syntax. + - job: secrets_job + displayName: Generate Secrets + pool: + # We don't need anything special, so use the standard Microsoft-hosted Ubuntu image, which + # is typically very fast to spin up. + vmImage: ubuntu-latest + + steps: + + # We don't need the repo checked out. + - checkout: none + + # Generate a password suitable for the SA user of local SQL Server instances. + # This creates the SaPassword.Value variable. + - bash: | + guid=$(cat /proc/sys/kernel/random/uuid) + echo "##vso[task.setvariable variable=Value;isOutput=true]$guid" + name: SaPassword + displayName: Generate SA password + + # Emit the SA password, if desired. + - ${{ if eq(parameters.debug, true) }}: + - bash: | + echo "SA password: $(SaPassword.Value)" + displayName: '[Debug] Emit SA password' diff --git a/eng/pipelines/pr/stages/pack-stage.yml b/eng/pipelines/pr/stages/pack-stage.yml new file mode 100644 index 0000000000..c0a135e246 --- /dev/null +++ b/eng/pipelines/pr/stages/pack-stage.yml @@ -0,0 +1,128 @@ +################################################################################# +# 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. # +################################################################################# + +# This stage is meant to perform a sanity check of the source code at the current point in time. +# Although the test targets will implicitly build the projects they depend on, this stage allows +# for fast failure of the build if the source code is not in a state that can be built. +# +# This stage will also be used to generate nuget packages based on the current source code. These +# will be uploaded, along with the build output as the artifacts of the build. +# +# Developer notes --- +# * Because we want a single artifact for build output, and we want to minimize overhead for build, +# we build all packages as a single job rather than one job per package. +# * Although theoretically in package build we could arrange build steps to minimize re-building, +# build.proj isn't properly aware of how to do this. So, instead, arranging the build steps +# alphabetically is the best way to arrange for now. + +parameters: + + # Configuration with which to build the packages and execute the tests. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to append to the package version to indicate it is a pre-release/development build. + - name: buildSuffix + type: string + + # Name to use for the stage. This is parameterized to allow a higher level of the pipeline to + # define the name and pass it to sibling stages (ie, test stage) and avoid relying on brittle + # hard-coded stage names. + - name: stageName + type: string + +stages: + - stage: ${{ parameters.stageName }} + displayName: Build and Pack Projects + dependsOn: [] + + jobs: + - job: pack_job + displayName: Build and Pack Projects + + pool: + vmImage: 'ubuntu-latest' + + steps: + # Install dotnet SDK and restore tools + - template: /eng/pipelines/pr/steps/install-dotnet.yml@self + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeeded() # Only run if dotnet was installed successfully + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: SqlClient + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeededOrFailed() + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: AkvProvider + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Extensions.Abstractions + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeededOrFailed() + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Abstractions + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Extensions.Azure + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeededOrFailed() + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Azure + + # ################################################################ + # Build/Pack Microsoft.Data.SqlClient.Internal.Logging + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeededOrFailed() + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: Logging + + # ################################################################ + # Build/Pack Microsoft.SqlServer.Server + - template: /eng/pipelines/pr/steps/pack-buildproj-step.yml + parameters: + condition: succeededOrFailed() + + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + packageShortName: SqlServer + + # Emit the build output + - script: tree -a $(BUILD_OUTPUT) + displayName: Output Build Output Tree + condition: succeededOrFailed() + + # Upload the build output as the artifact of the job + - publish: $(BUILD_OUTPUT) + artifact: build_and_pack_projects + condition: succeededOrFailed() + + + + diff --git a/eng/pipelines/pr/stages/test-stages.yml b/eng/pipelines/pr/stages/test-stages.yml new file mode 100644 index 0000000000..f2ffbc09cf --- /dev/null +++ b/eng/pipelines/pr/stages/test-stages.yml @@ -0,0 +1,197 @@ +################################################################################# +# 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. # +################################################################################# + +# These stages are meant to validate a PR against a battery of tests to ensure confidence in the +# changes the PR presents. There is, however, a balance to be struck between completeness of +# confidence and expedience of validation. + +parameters: + # Configuration with which to build the packages and execute the tests. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to append to the package version to indicate it is a pre-release/development build. + - name: buildSuffix + type: string + + # Name of the build/pack stage that this stage will depend on. + - name: stageNamePack + type: string + + # Name of the secret generation job used to determine the path to the SA password variable. + - name: stageNameSecrets + type: string + + # Name of the pool to use for jobs that require customized VM images. + - name: poolName + type: string + + # Manual Test Configuration Parameters ================================== + + # Azure Key Vault tenant ID that will be set in the config.json file for sqlclient manual tests. + - name: manualTestAzureKeyVaultTenantId + type: string + + # Azure Key Vault URL that will be set in the config.json file for sqlclient manual tests. + - name: manualTestAzureKeyVaultUrl + type: string + + # Connection string to Azure SQL using named pipes that will be set in the config.json file for + # sqlclient manual tests against Azure SQL. + - name: manualTestConnectionStringNpAzure + type: string + + # Connection string to localhost using named pipes that will be set in the config.json file for + # sqlclient manual tests against a local box product. + - name: manualTestConnectionStringNpLocalhost + type: string + + # Connection string to Azure SQL using TCP that will be set in the config.json file for sqlclient + # manual tests against Azure SQL. + - name: manualTestConnectionStringTcpAzure + type: string + + # Connection string to localhost using TCP that will be set in the config.json file for sqlclient + # manual tests against a local box product. + - name: manualTestConnectionStringTcpLocalhost + type: string + + # Path to use for file stream tests, this value will be stored in the config.json for sqlclient + # manual tests. + - name: manualTestFileStreamDirectory + type: string + + # Name of the local DB application name for localdb tests, this value will be stored in the + # config.json for sqlclient manual tests. + - name: manualTestLocalDbAppName + type: string + + # Name of the local DB shared instance name for localdb tests, this value will be stored in the + # config.json for sqlclient manual tests. + - name: manualTestLocalDbSharedInstanceName + type: string + + # This is an array of objects with the following fields: + # - displayName - Friendly name to use when displaying the stage name and job names. This + # must only contain alphanumeric characters and '_'. It will be used for both + # display name fields and stage/job names. + # - dotnet - Version of dotnet runtime to use to execute the tests + # - image - Image to use to execute the test jobs in the pipeline + # - operatingSystem - General OS "class" that the image contains. This is used to switch between + # server configuration behaviors. + # + # Each one of the objects in this parameter will become a stage that executes all test projects + # available. + - name: platforms + type: object + default: [] + +stages: + - ${{ each platform in parameters.platforms }}: + - stage: "test_${{ platform.displayName }}" + displayName: "Test: ${{ platform.displayName }}" + dependsOn: + - ${{ parameters.stageNamePack }} + - ${{ parameters.stageNameSecrets }} + + jobs: + # TestAbstractions + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} + + packageShortName: "Abstractions" + testDisplayName: "abstractions" + + # TestAzure + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} + + packageShortName: "Azure" + testDisplayName: "azure" + + # TestSqlClientFunctional + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} + + packageShortName: "SqlClient" + testDisplayName: "sqlclient_functional" + testProject: "Functional" + + # TestSqlClientManual - Localhost + - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + stageNameSecrets: ${{ parameters.stageNameSecrets }} + + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + platformOperatingSystem: ${{ platform.operatingSystem }} + poolName: ${{ parameters.poolName }} + + azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} + azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} + connectionStringNp: ${{ parameters.manualTestConnectionStringNpLocalhost }} + connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpLocalhost }} + fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} + localDbAppName: ${{ parameters.manualTestLocalDbAppName }} + localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} + + # @TODO: +# # TestSqlClientManual - Azure +# - template: /eng/pipelines/pr/jobs/test-sqlclientmanual-job.yml@self +# parameters: +# buildConfiguration: ${{ parameters.buildConfiguration }} +# buildSuffix: ${{ parameters.buildSuffix }} +# platformDisplayName: ${{ platform.displayName }} +# platformDotnet: ${{ platform.dotnet }} +# platformImage: ${{ platform.image }} +# poolName: ${{ parameters.poolName }} +# +# azureKeyVaultTenantId: ${{ parameters.manualTestAzureKeyVaultTenantId }} +# azureKeyVaultUrl: ${{ parameters.manualTestAzureKeyVaultUrl }} +# connectionStringNp: ${{ parameters.manualTestConnectionStringNpAzure }} +# connectionStringTcp: ${{ parameters.manualTestConnectionStringTcpAzure }} +# fileStreamDirectory: ${{ parameters.manualTestFileStreamDirectory }} +# localDbAppName: ${{ parameters.manualTestLocalDbAppName }} +# localDbSharedInstanceName: ${{ parameters.manualTestLocalDbSharedInstanceName }} +# saPassword: $(manualTestSaPassword) + + # TestSqlClientUnit + - template: /eng/pipelines/pr/jobs/test-buildproj-job.yml@self + parameters: + buildConfiguration: ${{ parameters.buildConfiguration }} + buildSuffix: ${{ parameters.buildSuffix }} + platformDisplayName: ${{ platform.displayName }} + platformDotnet: ${{ platform.dotnet }} + platformImage: ${{ platform.image }} + poolName: ${{ parameters.poolName }} + + packageShortName: "SqlClient" + testDisplayName: "sqlclient_unit" + testProject: "Unit" diff --git a/eng/pipelines/pr/steps/build-buildproj-step.yml b/eng/pipelines/pr/steps/build-buildproj-step.yml new file mode 100644 index 0000000000..3e81edfbf4 --- /dev/null +++ b/eng/pipelines/pr/steps/build-buildproj-step.yml @@ -0,0 +1,46 @@ +################################################################################# +# 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. # +################################################################################# + +# This collection of steps to build a project via the build.proj. This will execute the "Build*" +# target in build.proj, where * is the packageShortName provided in the parameters. +# +# Note: This differs from the onebranch build-buildproj-step.yml in that it does *not* strong-name +# sign the assemblies, it only builds in project reference mode, and as such it does not allow +# version parameters or dependencies to be provided. + +parameters: + - name: buildConfiguration + type: string + values: + - Debug + - Release + + - name: buildSuffix + type: string + + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Build${{ parameters.packageShortName }}' + inputs: + command: build + projects: build.proj + arguments: >- + -t:Build${{ parameters.packageShortName }} + -p:Configuration=${{ parameters.buildConfiguration }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' + + diff --git a/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml new file mode 100644 index 0000000000..8eb8cc40d6 --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml @@ -0,0 +1,127 @@ +################################################################################# +# 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. # +################################################################################# + +# This step configures an existing SQL Server running on the local Linux host. For example, our 1ES +# Hosted Pool has images like ADO-UB20-SQL22 that come with SQL Server 2022 pre-installed and +# running. + +parameters: + + # The SA password to set when configuring SQL Server. + - name: saPassword + type: string + +steps: + + # Configure SQL Server. + - bash: | + set -u + + if ! command -v sudo >/dev/null 2>&1; then + echo "ERROR: 'sudo' is required to configure SQL Server on Linux." + exit 1 + fi + + if [ ! -x /opt/mssql/bin/mssql-conf ]; then + echo "ERROR: '/opt/mssql/bin/mssql-conf' was not found." + exit 1 + fi + + SQLCMD_BIN="" + if command -v sqlcmd >/dev/null 2>&1; then + SQLCMD_BIN="$(command -v sqlcmd)" + elif [ -x /opt/mssql-tools18/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools18/bin/sqlcmd" + elif [ -x /opt/mssql-tools/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools/bin/sqlcmd" + else + echo "ERROR: 'sqlcmd' was not found on PATH or in the standard mssql-tools locations." + exit 1 + fi + + sudo systemctl stop mssql-server + errstatus=$? + if [ $errstatus -ne 0 ] + then + echo "ERROR: stopping mssql-server failed with exit code $errstatus." + exit $errstatus + fi + + # Password for the SA user (required) + MSSQL_SA_PW="${{ parameters.saPassword }}" + + # Product ID of the version of SQL server you're installing + # Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key + MSSQL_PID="enterprise" + + echo Running mssql-conf setup... + sudo MSSQL_SA_PASSWORD="$MSSQL_SA_PW" \ + MSSQL_PID="$MSSQL_PID" \ + /opt/mssql/bin/mssql-conf -n setup accept-eula + errstatus=$? + if [ $errstatus -ne 0 ] + then + echo "ERROR: mssql-conf setup failed with exit code $errstatus." + exit $errstatus + fi + + # Connect to server and get the version: + counter=1 + errstatus=1 + while [ $counter -le 5 ] && [ $errstatus -ne 0 ] + do + echo Waiting for SQL Server to start... + sleep 3s + "$SQLCMD_BIN" \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -Q "SELECT @@VERSION" 2>/dev/null + errstatus=$? + ((counter++)) + done + + # Display error if connection failed: + if [ $errstatus -ne 0 ] + then + echo Cannot connect to SQL Server, installation aborted + exit $errstatus + fi + displayName: 'Configure SQL Server [Linux]' + + - bash: | + set -u + + SCRIPT_PATH="$(Build.SourcesDirectory)/tools/testsql/createNorthwindDb.sql" + MSSQL_SA_PW="${{ parameters.saPassword }}" + + SQLCMD_BIN="" + if command -v sqlcmd >/dev/null 2>&1; then + SQLCMD_BIN="$(command -v sqlcmd)" + elif [ -x /opt/mssql-tools18/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools18/bin/sqlcmd" + elif [ -x /opt/mssql-tools/bin/sqlcmd ]; then + SQLCMD_BIN="/opt/mssql-tools/bin/sqlcmd" + else + echo "ERROR: 'sqlcmd' was not found on PATH or in the standard mssql-tools locations." + exit 1 + fi + + "$SQLCMD_BIN" \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -Q "IF DB_ID(N'Northwind') IS NOT NULL BEGIN ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [Northwind]; END" \ + -b + + "$SQLCMD_BIN" \ + -S localhost \ + -U SA \ + -P "$MSSQL_SA_PW" \ + -i "$SCRIPT_PATH" \ + -b + displayName: 'Create Northwind Database [Linux]' + retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/pr/steps/configure-sqlserver-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-step.yml new file mode 100644 index 0000000000..ebae5390e4 --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-step.yml @@ -0,0 +1,30 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + + # Path to use for file stream tests. This only applies to Windows test runs. + - name: fileStreamDirectory + type: string + + - name: operatingSystem + type: string + + # Password to use for the SA account. This should be generated from the generate-secrets-stage. + - name: saPassword + type: string + +steps: + - ${{ if eq(parameters.operatingSystem, 'Windows') }}: + - template: /eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml@self + parameters: + fileStreamDirectory: ${{ parameters.fileStreamDirectory }} + saPassword: ${{ parameters.saPassword }} + + - ${{ elseif eq(parameters.operatingSystem, 'Linux') }}: + - template: /eng/pipelines/pr/steps/configure-sqlserver-linux-step.yml@self + parameters: + saPassword: ${{ parameters.saPassword }} diff --git a/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml new file mode 100644 index 0000000000..d1567beaee --- /dev/null +++ b/eng/pipelines/pr/steps/configure-sqlserver-windows-step.yml @@ -0,0 +1,115 @@ +################################################################################# +# 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. # +################################################################################# + +# This step configures an existing SQL Server running on the local Windows host. For example, our +# 1ES Hosted Pool has images like ADO-MMS22-SQL22 that come with SQL Server 2022 pre-installed and +# running. + +parameters: + + # Path to use for file stream tests. + - name: fileStreamDirectory + type: string + + # Password to use for the SA account. This should be generated from the generate-secrets-stage. + - name: saPassword + type: string + +steps: + # GOTCHA: We must use the Windows-only powershell task here instead of the cross-platform pwsh + # task because we call some Windows-specific cmdlets. + + # Enable TCP and NP protocols on the default SQL Server instance + - powershell: | + try + { + echo "> 1. Acquire WMI handle" + Import-Module "sqlps" + $smo = 'Microsoft.SqlServer.Management.Smo.' + $wmi = new-object ($smo + 'Wmi.ManagedComputer') + + + Write-Host "WMI Information:" + $wmi + + echo "> 2. Enable TCP on the default instance" + $Tcp = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='MSSQLSERVER']/ServerProtocol[@Name='Tcp']") + $Tcp.IsEnabled = $true + $Tcp.Alter() + + Write-Host "TCP Information:" + $Tcp + + echo "> 3. Enable named pipes on the default instance" + $Np = $wmi.GetSmoObject("ManagedComputer[@Name='$env:COMPUTERNAME']/ ServerInstance[@Name='MSSQLSERVER']/ServerProtocol[@Name='Np']") + $Np.IsEnabled = $true + $Np.Alter() + + Write-Host "NP Information:" + $Np + } + catch + { + $error[0] | format-list -force + throw + } + + New-NetFirewallRule -DisplayName "SQL TCP Ports" -Direction Inbound -Protocol TCP -LocalPort 1433 -Action allow + $sqlSrvPath = (Get-WmiObject win32_service | ?{$_.DisplayName -eq 'SQL Server (MSSQLSERVER)'} | select @{Name="Path"; Expression={$_.PathName.split('"')[1]}}).Path + New-NetFirewallRule -DisplayName "sqlservr.exe" -Program "$sqlSrvPath" + displayName: 'Enable TCP, NP & Firewall [Win]' + retryCountOnTaskFailure: 2 + + # Set the SA password on the default instance + - powershell: | + # Propagate parameters to PS variables ############################### + $password = "${{ parameters.saPassword }}" + + # Connect to database and update SA account ########################## + Import-Module "sqlps" + $machineName = $env:COMPUTERNAME + + Invoke-Sqlcmd -ServerInstance "$machineName" @" + ALTER LOGIN [sa] ENABLE; + ALTER LOGIN [sa] WITH PASSWORD = '$password'; + "@ + displayName: 'Set SA Password [Win]' + retryCountOnTaskFailure: 5 + + # Create folder for file stream tests + - powershell: | + New-Item -Path ${{ parameters.fileStreamDirectory }} -ItemType Directory + displayName: 'Create FileStreamFolder' + retryCountOnTaskFailure: 1 + continueOnError: true + + # Install northwind database + - powershell: | + # Propagate parameters to PS variables ############################### + $repoRoot = "$(REPO_ROOT)" + echo "repoRoot= $repoRoot" + + # Install Northwind Database ######################################### + Import-Module "sqlps" + $machineName = $env:COMPUTERNAME + + # Delete any existing northwind database + Invoke-Sqlcmd ` + -ServerInstance "$machineName" ` + -Database "master" ` + -Query @" + IF DB_ID(N'Northwind') IS NOT NULL + BEGIN + ALTER DATABASE [Northwind] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + DROP DATABASE [Northwind]; + END + "@ + + # Install northwind database via script + $scriptPath = "$repoRoot\tools\testsql\createNorthwindDb.sql" + Invoke-Sqlcmd -ServerInstance "$machineName" -Database "master" -InputFile $scriptPath + displayName: 'Create Northwind Database [Win]' + retryCountOnTaskFailure: 1 diff --git a/eng/pipelines/pr/steps/install-dotnet.yml b/eng/pipelines/pr/steps/install-dotnet.yml new file mode 100644 index 0000000000..fe1c8f7878 --- /dev/null +++ b/eng/pipelines/pr/steps/install-dotnet.yml @@ -0,0 +1,27 @@ +################################################################################# +# 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. # +################################################################################# + +# This is a step to wrap the install-dotnet step for use in the PR pipeline. It will always install +# the SDK version specified in the global.json file, and if the runtime version specified does not +# begin with "net4" (ie, indicating netfx runtime is being used), the version will be passed in as +# part of the runtime parameters. +# +# This version chains into the common install-dotnet step to enable the pr pipeline to call a +# single step template and get the desired behavior without complexity. + +parameters: + - name: runtimeVersion + type: string + default: '' + +steps: + - template: /eng/pipelines/common/steps/install-dotnet.yml@self + parameters: + ${{ if and( not(eq(parameters.runtimeVersion, '' )), not(contains(parameters.runtimeVersion, 'net4')) ) }}: + runtimes: + - "${{ replace(parameters.runtimeVersion, 'net', '') }}.x" + + - template: /eng/pipelines/common/steps/restore-dotnet-tools.yml@self diff --git a/eng/pipelines/pr/steps/pack-buildproj-step.yml b/eng/pipelines/pr/steps/pack-buildproj-step.yml new file mode 100644 index 0000000000..6b2980cbb4 --- /dev/null +++ b/eng/pipelines/pr/steps/pack-buildproj-step.yml @@ -0,0 +1,59 @@ +################################################################################# +# 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. # +################################################################################# + +# This is a step to build a project via the build.proj. This will execute the "Pack*" target in +# build.proj, where * is the packageShortName provided in the parameters. Because the "no build" +# parameter is not provided, the target will implicitly build the projects required to create the +# NuGet package. + +parameters: + # General Parameters ===================================================== + + # Condition parameter to forward onto the DotNetCoreCLI task. + - name: condition + type: string + default: succeeded() + + # Build Parameters ======================================================= + + # Configuration to use to build the project. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to apply to the generated packages such that the package will be considered a prerelease + # version. The resulting package version will look like: `1.2.3-suffix888.1` where 1.2.3 is the + # default version specified in Versions.props, suffix is this parameter, and 888.1 is the build + # number for the currently executing build. + - name: buildSuffix + type: string + + # Package/project to build and pack. + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Build${{ parameters.packageShortName }}' + condition: ${{ parameters.condition }} + inputs: + command: build + projects: build.proj + verbosity: detailed + arguments: >- + -t:Pack${{ parameters.packageShortName }} + -p:Configuration=${{ parameters.buildConfiguration }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' diff --git a/eng/pipelines/pr/steps/test-buildproj-step.yml b/eng/pipelines/pr/steps/test-buildproj-step.yml new file mode 100644 index 0000000000..5309e7ef96 --- /dev/null +++ b/eng/pipelines/pr/steps/test-buildproj-step.yml @@ -0,0 +1,59 @@ +################################################################################# +# 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. # +################################################################################# + +parameters: + # General Parameters ======================================================= + + # Configuration to use to build the project. + - name: buildConfiguration + type: string + values: + - Debug + - Release + + # Suffix to apply to the generated packages such that the package will be considered a prerelease + # version. The resulting package version will look like: `1.2.3-suffix888.1` where 1.2.3 is the + # default version specified in Versions.props, suffix is this parameter, and 888.1 is the build + # number for the currently executing build. + - name: buildSuffix + type: string + + # Test Parameters ======================================================== + + # Package/project to test. + - name: packageShortName + type: string + values: + - Azure + - AkvProvider + - Abstractions + - Logging + - SqlClient + - SqlServer + + - name: testFramework + type: string + + # If the project to test has multiple projects supported by build.proj, use this optional + # parameter to specify the project to execute. This will be appended to Test{PackageShortName} to + # generate the target to execute. See build.proj for supported targets. + - name: testProject + type: string + default: '' + +steps: + - task: DotNetCoreCLI@2 + displayName: 'build.proj - Test${{ parameters.packageShortName }}${{ parameters.testProject }}' + inputs: + command: build + projects: build.proj + verbosity: detailed + arguments: >- + -t:Test${{ parameters.packageShortName }}${{ parameters.testProject }} + -p:Configuration=${{ parameters.buildConfiguration }} + -p:BuildNumber='$(Build.BuildNumber)' + -p:BuildSuffix='${{ parameters.buildSuffix }}' + -p:TestFramework=${{ parameters.testFramework }} diff --git a/eng/pipelines/pr/variables/pr-variables.yml b/eng/pipelines/pr/variables/pr-variables.yml new file mode 100644 index 0000000000..4a28253dc7 --- /dev/null +++ b/eng/pipelines/pr/variables/pr-variables.yml @@ -0,0 +1,30 @@ +################################################################################# +# 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. # +################################################################################# + +# This file contains variables used for running PR pipelines. + +variables: + # Libraries ============================================================== + + # These variables are used to construct the config file for manual tests. + # + # AzureKeyVaultTenantId + # AzureKeyVaultUrl + # ConnectionStringNp_Azure_ManagedIdentity + # ConnectionStringNp_LocalhostDefault_UsernamePassword + # ConnectionStringTcp_Azure_ManagedIdentity + # ConnectionStringTcp_LocalhostDefault_UsernamePassword + # LocalDbAppName + # LocalDbSharedInstanceName + # PoolNameDefault + - group: sqlclient-testconfig-v1 + + # General Variables ====================================================== + - name: stageNamePack + value: "pack_stage" + + - name: stageNameSecrets + value: "secrets_stage" diff --git a/eng/pipelines/stress/stress-tests-job.yml b/eng/pipelines/stress/stress-tests-job.yml index a216c23864..ac82002ece 100644 --- a/eng/pipelines/stress/stress-tests-job.yml +++ b/eng/pipelines/stress/stress-tests-job.yml @@ -144,7 +144,7 @@ jobs: steps: # Install the .NET SDK and Runtimes. - - template: /eng/pipelines/steps/install-dotnet.yml@self + - template: /eng/pipelines/common/steps/install-dotnet.yml@self parameters: runtimes: [8.x, 9.x] diff --git a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs index 43c7bde4bd..8851cb5210 100644 --- a/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs +++ b/src/Microsoft.Data.SqlClient/tests/Common/SqlDataReaderExtensions.cs @@ -2,6 +2,8 @@ // 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.Threading.Tasks; + namespace Microsoft.Data.SqlClient.Tests.Common { /// @@ -21,6 +23,19 @@ public static void FlushAllResults(this SqlDataReader dataReader) } while (dataReader.NextResult()); } + /// + /// Reads all result sets in the provided and discards them + /// asynchronously. + /// + /// Reader to flush results from. + public static async Task FlushAllResultsAsync(this SqlDataReader dataReader) + { + do + { + await dataReader.FlushResultSetAsync(); + } while (await dataReader.NextResultAsync()); + } + /// /// Reads all results in the current result set of the provided /// and discards them. @@ -33,5 +48,18 @@ public static void FlushResultSet(this SqlDataReader dataReader) // Discard results. } } + + /// + /// Reads all results in the current result set of the provided + /// and discards them asynchronously. + /// + /// Reader to flush results from. + public static async Task FlushResultSetAsync(this SqlDataReader dataReader) + { + while (await dataReader.ReadAsync()) + { + // Discard results. + } + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 1c16e90ac4..620d7bd99a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -14,13 +14,18 @@ using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; using Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals; +using Microsoft.Data.SqlClient.Tests.Common; using Xunit; +using CommonObjects = Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects; + namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { /// /// Always Encrypted public API Manual tests. /// + // @TODO: These tests are known to not run reliably in DEBUG mode. + [ConditionalClass(typeof(DataTestUtility), nameof(DataTestUtility.IsNotDebugBuild))] public sealed class ApiShould : IClassFixture, IDisposable { private SQLSetupStrategy _fixture; @@ -726,37 +731,41 @@ public void TestExecuteReader(string connection) [ClassData(typeof(AEConnectionStringProvider))] public async Task TestExecuteReaderAsyncWithLargeQuery(string connectionString) { - string randomName = DataTestUtility.GetShortName(Guid.NewGuid().ToString().Replace("-", ""), false); - if (randomName.Length > 50) - { - randomName = randomName.Substring(0, 50); - } - string tableName = $"VeryLong_{randomName}_TestTableName"; - int columnsCount = 50; - - // Arrange - drops the table with long name and re-creates it with 52 columns (ID, name, ColumnName0..49) - using SqlConnection connection = new SqlConnection(connectionString); + // Arrange + // - Set up connection to run the test + using SqlConnection connection = new(connectionString); await connection.OpenAsync(); - using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects.Table wideTable = new(connection, tableName, GenerateBitTableDefinition(columnsCount)); - string name = "nobody"; + // - Drop and create table with 52 columns (ID, name, ColumnName0..49) + string tableName = DataTestUtility.GetShortName("VeryLongTestTableName_", withBracket: false); + const int columnsCount = 50; + using CommonObjects.Table wideTable = new(connection, tableName, GenerateBitTableDefinition(columnsCount)); - // This creates a "select top 100" query that has over 40k characters - using SqlCommand sqlCommand = new(GenerateSelectQuery(wideTable.Name, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"), + // - Create SELECT query that has over 40k characters *and repeats 10 times* + using SqlCommand sqlCommand = new( + GenerateSelectQuery(wideTable.Name, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"), connection, transaction: null, columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled); - sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); - sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar, name.Length); - sqlCommand.Parameters[0].Value = 0; - sqlCommand.Parameters[1].Value = name; + SqlParameter parameter1 = sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); + parameter1.Value = 0; + + SqlParameter parameter2 = sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar); + parameter2.Value = "nobody"; - // Act and Assert - // Test that execute reader async does not throw an exception. - // The table is empty so there should be no results; however, the bug previously found is that it causes a TDS RPC exception on enclave. + // Act using SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(); + + // Assert + // - The table is empty so there should be no results; however, the bug previously + // found is that it causes a TDS RPC exception on enclave. Assert.False(sqlDataReader.HasRows, "The table should be empty"); + + // Cleanup + // - Explicitly throw away the results from the reader to avoid any race conditions in + // disposal logic. + await sqlDataReader.FlushAllResultsAsync(); } [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsTargetReadyForAeWithKeyStore))] @@ -1914,7 +1923,7 @@ public void TestExecuteXmlReader(string connection) IList values = GetValues(dataHint: 60); int numberOfRows = 10; - // Insert a bunch of rows in to the table. + // Insert a bunch of rows in to the table. int rowsAffected = InsertRows(tableName: _tableName, numberofRows: numberOfRows, values: values, connection: connection); Assert.True(rowsAffected == numberOfRows, "number of rows affected is unexpected."); @@ -1922,12 +1931,12 @@ public void TestExecuteXmlReader(string connection) { sqlConnection.Open(); - // select the set of rows that were inserted just now. + // select the set of rows that were inserted just now. using (SqlCommand sqlCommand = new SqlCommand($"SELECT LastName FROM [{_tableName}] WHERE FirstName = @FirstName AND CustomerId = @CustomerId FOR XML AUTO;", sqlConnection, transaction: null, columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled)) { if (DataTestUtility.EnclaveEnabled) { - //Increase Time out for enclave-enabled server. + //Increase Time out for enclave-enabled server. sqlCommand.CommandTimeout = 90; } sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); @@ -2031,7 +2040,7 @@ public void TestSqlCommandCancel(string connection, string value) * Use long-running tasks to create the thread. This enables any failed assertions to propagate, rather than * allowing the exception to kill the thread and the process. * These threads should progress in the sequence below: - * + * * Workload Thread | Cancel Thread * ------------------------------------ | ------------- * Start thread | Start thread @@ -2307,7 +2316,7 @@ public void TestConnectionCustomKeyStoreProviderDuringAeQuery(string connectionS () => ExecuteQueryThatRequiresCustomKeyStoreProvider(connection)); AssertExceptionCausedByFailureToDecrypt(ex); - // not required provider will replace the previous entry so required provider will not be found + // not required provider will replace the previous entry so required provider will not be found connection.RegisterColumnEncryptionKeyStoreProvidersOnConnection(_notRequiredProvider); ex = Assert.Throws( () => ExecuteQueryThatRequiresCustomKeyStoreProvider(connection)); @@ -2448,7 +2457,7 @@ public void TestRetryWhenAEParameterMetadataCacheIsStale(string connectionString cmd.CommandText = string.Format(alterCekQueryFormatString, _tableName, table.columnEncryptionKey2.Name); cmd.ExecuteNonQuery(); - // execute the select query again. it will attempt to use the stale cache entry, receive + // execute the select query again. it will attempt to use the stale cache entry, receive // a retryable error from the server, remove the stale cache entry, retry and succeed cmd.CommandText = enclaveSelectQuery; cmd.Parameters.AddWithValue("@CustomerId", 0); @@ -2562,7 +2571,7 @@ public void TestRetryWhenAEEnclaveCacheIsStale(string connectionString) readAsyncTask2.GetAwaiter().GetResult(); #endif */ - + // revert the CEK change to the CustomerId column cmd.Parameters.Clear(); cmd.CommandText = string.Format(alterCekQueryFormatString, _tableName, table.columnEncryptionKey1.Name); @@ -2699,8 +2708,8 @@ private DataTable CreateDataTable(string tableName, int numberofRows) }; table.Columns.Add(column); - // Create three new DataRow objects and add - // them to the DataTable + // Create three new DataRow objects and add + // them to the DataTable for (int i = 0; i < numberofRows; i++) { row = table.NewRow(); @@ -2810,7 +2819,7 @@ private async Task VerifyExecuteScalarAsync(SqlCommand sqlCommand) } /// - /// + /// /// /// /// @@ -2821,7 +2830,7 @@ private async Task ExecuteNonQueryAsync(SqlCommand sqlCommand, CancellationToken } /// - /// + /// /// /// /// diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 623f645ddb..9bf1c0f519 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -188,6 +188,20 @@ public static string SQLServerVersion IsSqlVectorSupported && CheckVectorFloat16Supported(); + public static bool IsDebugBuild + { + get + { + #if DEBUG + return true; + #else + return false; + #endif + } + } + + public static bool IsNotDebugBuild() => !IsDebugBuild; + private static bool CheckVectorFloat16Supported() { try diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs index 42a2331be6..cba6712065 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs @@ -22,16 +22,10 @@ public static class InstanceNameTest public static void ConnectToSQLWithInstanceNameTest() { SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + DataTestUtility.ParseDataSource(builder.DataSource, out string hostname, out _, out _); - bool proceed = true; - string dataSourceStr = builder.DataSource.Replace("tcp:", ""); - string[] serverNamePartsByBackSlash = dataSourceStr.Split('\\'); - string hostname = serverNamePartsByBackSlash[0]; - if (!dataSourceStr.Contains(",") && serverNamePartsByBackSlash.Length == 2) - { - proceed = !string.IsNullOrWhiteSpace(hostname) && IsBrowserAlive(hostname); - } - + // @TODO: This test as it is written will report success even if it doesn't test anything. + bool proceed = !string.IsNullOrWhiteSpace(hostname) && IsBrowserAlive(hostname); if (proceed) { using SqlConnection connection = new(builder.ConnectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs index 552fd4cea5..04b0de8072 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs @@ -150,6 +150,8 @@ public static void CancelAndDisposePreparedCommand_NamedPipe() => public static void TimeOutDuringRead_Tcp() => TimeOutDuringRead(tcp_connStr); + // @TODO: This test does not test NP behavior as the proxy server converts the named pipe connection string to a TCP connection string. + [ActiveIssue("https://dev.azure.com/SqlClientDrivers/ADO.Net/_workitems/edit/40840/")] [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotNamedInstance))] [PlatformSpecific(TestPlatforms.Windows)] public static void TimeOutDuringRead_NamedPipe() => diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs index e4bd1133ac..24f34bbf12 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs @@ -11,7 +11,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests public sealed class SqlNotificationTest : IDisposable { // Misc constants - private const int CALLBACK_TIMEOUT = 5000; // milliseconds + private const int CALLBACK_TIMEOUT = 20000; // milliseconds // Database schema private readonly string _tableName = $"dbo.[SQLDEP_{Guid.NewGuid().ToString()}]"; @@ -143,6 +143,7 @@ public void Test_SingleDependency_Stopped() } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))] + [Trait("Category", "flaky")] public void Test_SingleDependency_AllDefaults_SqlAuth() { Assert.True(SqlDependency.Start(_startConnectionString), "Failed to start listener."); 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..b2200b03c0 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 }