From 4018513d56fcfc3851a5c49c0b8e68feaa7c466c Mon Sep 17 00:00:00 2001 From: Vincent Dai <23257217+vidai-msft@users.noreply.github.com> Date: Mon, 17 Apr 2023 23:58:32 -0700 Subject: [PATCH] Implemented live test email notification (#21565) --- .azure-pipelines/live-test.yml | 250 ++++++++++-------- .azure-pipelines/util/live-test-steps.yml | 3 +- ...led.ps1 => TestLiveScenarios.disabled.ps1} | 0 tools/TestFx/Live/SaveLiveTestResult.ps1 | 12 +- tools/TestFx/Live/SendLiveTestReport.ps1 | 97 +++++++ .../TestFx/Utilities/EmailServiceUtility.psd1 | 136 ++++++++++ .../TestFx/Utilities/EmailServiceUtility.psm1 | 57 ++++ tools/TestFx/Utilities/KustoUtility.psd1 | 2 +- tools/TestFx/Utilities/KustoUtility.psm1 | 76 ++++-- 9 files changed, 483 insertions(+), 150 deletions(-) rename src/BotService/LiveTests/{TestLiveScenarios_disabled.ps1 => TestLiveScenarios.disabled.ps1} (100%) create mode 100644 tools/TestFx/Live/SendLiveTestReport.ps1 create mode 100644 tools/TestFx/Utilities/EmailServiceUtility.psd1 create mode 100644 tools/TestFx/Utilities/EmailServiceUtility.psm1 diff --git a/.azure-pipelines/live-test.yml b/.azure-pipelines/live-test.yml index 90d1d9bfefa3..31a8ee275b84 100644 --- a/.azure-pipelines/live-test.yml +++ b/.azure-pipelines/live-test.yml @@ -1,17 +1,17 @@ parameters: -- name: img_windows_2019 +- name: os_windows_2019 displayName: Windows 2019 Image Version type: string default: windows-2019 -- name: img_windows_2022 +- name: os_windows_2022 displayName: Windows 2022 Image Version type: string default: windows-2022 -- name: img_linux +- name: os_linux displayName: Linux Image Version type: string default: ubuntu-20.04 -- name: img_macos +- name: os_macos displayName: MacOS Image Version type: string default: macOS-11 @@ -55,115 +55,133 @@ schedules: pr: none trigger: none -jobs: -- template: util/live-test-steps.yml - parameters: - name: 'win_ps_5_1_win_2019' - vmImage: ${{ parameters.img_windows_2019 }} - osType: 'Windows' - psVersion: ${{ parameters.win_ps_5_1 }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'win_ps_5_1_win_2022' - vmImage: ${{ parameters.img_windows_2022 }} - osType: 'Windows' - psVersion: ${{ parameters.win_ps_5_1 }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_2_x_win_2019' - vmImage: ${{ parameters.img_windows_2019 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_7_2_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_3_x_win_2019' - vmImage: ${{ parameters.img_windows_2019 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_7_3_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_latest_win_2019' - vmImage: ${{ parameters.img_windows_2019 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_latest }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_2_x_win_2022' - vmImage: ${{ parameters.img_windows_2022 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_7_2_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_3_x_win_2022' - vmImage: ${{ parameters.img_windows_2022 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_7_3_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_latest_win_2022' - vmImage: ${{ parameters.img_windows_2022 }} - osType: 'Windows' - psVersion: ${{ parameters.ps_latest }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_2_x_linux' - vmImage: ${{ parameters.img_linux }} - osType: 'Linux' - psVersion: ${{ parameters.ps_7_2_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_3_x_linux' - vmImage: ${{ parameters.img_linux }} - osType: 'Linux' - psVersion: ${{ parameters.ps_7_3_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_latest_linux' - vmImage: ${{ parameters.img_linux }} - osType: 'Linux' - psVersion: ${{ parameters.ps_latest }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_2_x_macOS' - vmImage: ${{ parameters.img_macos }} - osType: 'MacOS' - psVersion: ${{ parameters.ps_7_2_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_6 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_7_3_x_macOS' - vmImage: ${{ parameters.img_macos }} - osType: 'MacOS' - psVersion: ${{ parameters.ps_7_3_x }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} - -- template: util/live-test-steps.yml - parameters: - name: 'ps_latest_macOS' - vmImage: ${{ parameters.img_macos }} - osType: 'MacOS' - psVersion: ${{ parameters.ps_latest }} - dotnetVersion: ${{ parameters.dotnet_sdk_7 }} +stages: +- stage: Test + displayName: Run Live Test + jobs: + - template: util/live-test-steps.yml + parameters: + name: 'win_ps_5_1_win_2019' + vmImage: ${{ parameters.os_windows_2019 }} + osType: 'Windows' + psVersion: ${{ parameters.win_ps_5_1 }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'win_ps_5_1_win_2022' + vmImage: ${{ parameters.os_windows_2022 }} + osType: 'Windows' + psVersion: ${{ parameters.win_ps_5_1 }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_2_x_win_2019' + vmImage: ${{ parameters.os_windows_2019 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_7_2_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_3_x_win_2019' + vmImage: ${{ parameters.os_windows_2019 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_7_3_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_latest_win_2019' + vmImage: ${{ parameters.os_windows_2019 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_latest }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_2_x_win_2022' + vmImage: ${{ parameters.os_windows_2022 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_7_2_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_3_x_win_2022' + vmImage: ${{ parameters.os_windows_2022 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_7_3_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_latest_win_2022' + vmImage: ${{ parameters.os_windows_2022 }} + osType: 'Windows' + psVersion: ${{ parameters.ps_latest }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_2_x_linux' + vmImage: ${{ parameters.os_linux }} + osType: 'Linux' + psVersion: ${{ parameters.ps_7_2_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_3_x_linux' + vmImage: ${{ parameters.os_linux }} + osType: 'Linux' + psVersion: ${{ parameters.ps_7_3_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_latest_linux' + vmImage: ${{ parameters.os_linux }} + osType: 'Linux' + psVersion: ${{ parameters.ps_latest }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_2_x_macOS' + vmImage: ${{ parameters.os_macos }} + osType: 'MacOS' + psVersion: ${{ parameters.ps_7_2_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_6 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_7_3_x_macOS' + vmImage: ${{ parameters.os_macos }} + osType: 'MacOS' + psVersion: ${{ parameters.ps_7_3_x }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + + - template: util/live-test-steps.yml + parameters: + name: 'ps_latest_macOS' + vmImage: ${{ parameters.os_macos }} + osType: 'MacOS' + psVersion: ${{ parameters.ps_latest }} + dotnetVersion: ${{ parameters.dotnet_sdk_7 }} + +- stage: Report + displayName: Send Report + dependsOn: Test + jobs: + - job: + displayName: Send Live Test Status Report + steps: + - task: PowerShell@2 + displayName: Send live test report + inputs: + pwsh: true + targetType: filePath + filePath: ./tools/TestFx/Live/SendLiveTestReport.ps1 + arguments: $(KustoServicePrincipalTenantId) $(KustoServicePrincipalId) $(KustoServicePrincipalSecret) $(KustoClusterName) $(KustoClusterRegion) $(LiveTestDatabaseName) $(LiveTestTableName) $(Build.BuildId) "$(EmailServiceConnectionString)" "$(EmailFrom)" "$(EmailTo)" diff --git a/.azure-pipelines/util/live-test-steps.yml b/.azure-pipelines/util/live-test-steps.yml index 45b9f36f7649..190d369dd0d5 100644 --- a/.azure-pipelines/util/live-test-steps.yml +++ b/.azure-pipelines/util/live-test-steps.yml @@ -120,6 +120,7 @@ jobs: targetType: filePath filePath: ./tools/TestFx/Live/InvokeLiveTestCITask.ps1 arguments: -UseWindowsPowerShell ('${{ parameters.psVersion }}' -eq '5.1') -ScriptFile './tools/TestFx/Live/InvokeLiveTestScenarios.ps1 -RunPlatform ${{ parameters.osType }} -RunPowerShell ${{ parameters.psVersion }} -PowerShellLatest $(PowerShellLatest) -RepoLocation $(Build.SourcesDirectory) -DataLocation $(DataLocation)' + retryCountOnTaskFailure: 3 - task: PowerShell@2 displayName: Save live test results to Kusto @@ -135,6 +136,6 @@ jobs: - task: PublishPipelineArtifact@1 displayName: Publish live test results to pipeline artifact inputs: - artifact: livetest-os-${{ parameters.vmImage }}-powershell-${{ parameters.name }} + artifact: livetest-os-${{ parameters.vmImage }}-ps-${{ replace(parameters.psVersion, '*', 'x') }} targetPath: $(DataLocation) condition: always() diff --git a/src/BotService/LiveTests/TestLiveScenarios_disabled.ps1 b/src/BotService/LiveTests/TestLiveScenarios.disabled.ps1 similarity index 100% rename from src/BotService/LiveTests/TestLiveScenarios_disabled.ps1 rename to src/BotService/LiveTests/TestLiveScenarios.disabled.ps1 diff --git a/tools/TestFx/Live/SaveLiveTestResult.ps1 b/tools/TestFx/Live/SaveLiveTestResult.ps1 index 28212365268f..a32d1e122ee0 100644 --- a/tools/TestFx/Live/SaveLiveTestResult.ps1 +++ b/tools/TestFx/Live/SaveLiveTestResult.ps1 @@ -69,16 +69,8 @@ if (![string]::IsNullOrWhiteSpace($liveTestResults)) { Export-Csv -Path $_ -Encoding utf8 -NoTypeInformation -Force } - Import-Module "./tools/TestFx/Utilities/KustoUtility.psd1" -Force - Import-KustoDataFromCsv ` - -ServicePrincipalTenantId $ServicePrincipalTenantId ` - -ServicePrincipalId $ServicePrincipalId ` - -ServicePrincipalSecret $ServicePrincipalSecret ` - -ClusterName $ClusterName ` - -ClusterRegion $ClusterRegion ` - -DatabaseName $DatabaseName ` - -TableName $TableName ` - -CsvFile $liveTestResults + Import-Module "./tools/TestFx/Utilities/KustoUtility.psd1" -ArgumentList $ServicePrincipalTenantId, $ServicePrincipalId, $ServicePrincipalSecret, $ClusterName, $ClusterRegion -Force + Import-KustoDataFromCsv -DatabaseName $DatabaseName -TableName $TableName -CsvFile $liveTestResults } else { Write-Host "##[warning]No live test data was found." diff --git a/tools/TestFx/Live/SendLiveTestReport.ps1 b/tools/TestFx/Live/SendLiveTestReport.ps1 new file mode 100644 index 000000000000..934594190a8c --- /dev/null +++ b/tools/TestFx/Live/SendLiveTestReport.ps1 @@ -0,0 +1,97 @@ +param ( + [Parameter(Mandatory, Position = 0)] + [ValidateNotNullOrEmpty()] + [guid] $ServicePrincipalTenantId, + + [Parameter(Mandatory, Position = 1)] + [ValidateNotNullOrEmpty()] + [guid] $ServicePrincipalId, + + [Parameter(Mandatory, Position = 2)] + [ValidateNotNullOrEmpty()] + [string] $ServicePrincipalSecret, + + [Parameter(Mandatory, Position = 3)] + [ValidateNotNullOrEmpty()] + [string] $ClusterName, + + [Parameter(Mandatory, Position = 4)] + [ValidateNotNullOrEmpty()] + [string] $ClusterRegion, + + [Parameter(Mandatory, Position = 5)] + [ValidateNotNullOrEmpty()] + [string] $DatabaseName, + + [Parameter(Mandatory, Position = 6)] + [ValidateNotNullOrEmpty()] + [string] $TableName, + + [Parameter(Mandatory, Position = 7)] + [ValidateNotNullOrEmpty()] + [string] $BuildId, + + [Parameter(Mandatory, Position = 8)] + [ValidateNotNullOrEmpty()] + [string] $EmailServiceConnectionString, + + [Parameter(Mandatory, Position = 9)] + [ValidateNotNullOrEmpty()] + [string] $EmailFrom, + + [Parameter(Mandatory, Position = 10)] + [ValidateNotNullOrEmpty()] + [string] $EmailTo +) + +$utilDir = Join-Path -Path ($PSScriptRoot | Split-Path) -ChildPath "Utilities" + +$kustoUtil = $utilDir | Join-Path -ChildPath "KustoUtility.psd1" +Import-Module $kustoUtil -ArgumentList $ServicePrincipalTenantId, $ServicePrincipalId, $ServicePrincipalSecret, $ClusterName, $ClusterRegion -Force + +$query = @" + $TableName + | where BuildId == $BuildId and IsSuccess == false + | project BuildId, OSVersion, PSVersion, Module, Name, Exception = tostring(Errors["Exception"]), RetryException = tostring(Errors["Retry3Exception"]) +"@ +$errors = Get-KustoQueryData -DatabaseName $DatabaseName -Query $query +$errors + +$emailSvcUtil = $utilDir | Join-Path -ChildPath "EmailServiceUtility.psd1" +Import-Module $emailSvcUtil -ArgumentList $EmailServiceConnectionString, $EmailFrom -Force + +$css = @" + +"@ + +$emailSubject = "Live Test Status Report" + +if ($errors.Count -gt 0) { + $emailBody = $errors | ConvertTo-Html -Property BuildId, OSVersion, PSVersion, Module, Name, Exception, RetryException -Head $css -Title "Live Test Report" -PreContent "

Live Test Error Details

" +} +else { + $emailBody = "No live test errors reported. Please check the overall status from Azure pipeline." +} + +Send-EmailServiceMail -To $EmailTo -Subject $emailSubject -Body $emailBody diff --git a/tools/TestFx/Utilities/EmailServiceUtility.psd1 b/tools/TestFx/Utilities/EmailServiceUtility.psd1 new file mode 100644 index 000000000000..6c7b20714fd9 --- /dev/null +++ b/tools/TestFx/Utilities/EmailServiceUtility.psd1 @@ -0,0 +1,136 @@ +# ---------------------------------------------------------------------------------- +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------------- + +@{ + + # Script module or binary module file associated with this manifest. + RootModule = 'EmailServiceUtility.psm1' + + # Version number of this module. + ModuleVersion = '0.1.0' + + # Supported PSEditions + CompatiblePSEditions = 'Core', 'Desktop' + + # ID used to uniquely identify this module + GUID = 'aa8fed8f-bb02-43ae-974d-bf37ffa0e3ba' + + # Author of this module + Author = 'Microsoft Corporation' + + # Company or vendor of this module + CompanyName = 'Microsoft Corporation' + + # Copyright statement for this module + Copyright = 'Microsoft Corporation. All rights reserved.' + + # Description of the functionality provided by this module + Description = 'Utility for Azure Communication Services' + + # Minimum version of the PowerShell engine required by this module + PowerShellVersion = '5.1' + + # Name of the PowerShell host required by this module + # PowerShellHostName = '' + + # Minimum version of the PowerShell host required by this module + # PowerShellHostVersion = '' + + # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + DotNetFrameworkVersion = '4.7.2' + + # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. + # ClrVersion = '' + + # Processor architecture (None, X86, Amd64) required by this module + # ProcessorArchitecture = '' + + # Modules that must be imported into the global environment prior to importing this module + # RequiredModules = @() + + # Assemblies that must be loaded prior to importing this module + # RequiredAssemblies = @() + + # Script files (.ps1) that are run in the caller's environment prior to importing this module. + # ScriptsToProcess = @() + + # Type files (.ps1xml) to be loaded when importing this module + # TypesToProcess = @() + + # Format files (.ps1xml) to be loaded when importing this module + # FormatsToProcess = @() + + # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess + # NestedModules = @() + + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = 'Send-EmailServiceMail' + + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + CmdletsToExport = @() + + # Variables to export from this module + VariablesToExport = @() + + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + AliasesToExport = @() + + # DSC resources to export from this module + # DscResourcesToExport = @() + + # List of all modules packaged with this module + # ModuleList = @() + + # List of all files packaged with this module + # FileList = @() + + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + + # HelpInfo URI of this module + # HelpInfoURI = '' + + # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. + # DefaultCommandPrefix = '' + +} diff --git a/tools/TestFx/Utilities/EmailServiceUtility.psm1 b/tools/TestFx/Utilities/EmailServiceUtility.psm1 new file mode 100644 index 000000000000..63d357cf54de --- /dev/null +++ b/tools/TestFx/Utilities/EmailServiceUtility.psm1 @@ -0,0 +1,57 @@ +param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $EmailServiceConnectionString, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $EmailFrom +) + +function InitializeEmailServicePackages { + [CmdletBinding()] + param () + + $svcPackagesDirName = "EmailServicePackages" + $svcPackagesDir = Join-Path -Path . -ChildPath $svcPackagesDirName + if (Test-Path -LiteralPath $svcPackagesDir) { + Remove-Item -Path $svcPackagesDir -Recurse -Force + } + + New-Item -Path . -Name $svcPackagesDirName -ItemType Directory -Force + + $svcPackages = @( + @{ PackageName = "Azure.Communication.Email"; PackageVersion = "1.0.0"; DllName = "Azure.Communication.Email.dll" }, + @{ PackageName = "Azure.Core"; PackageVersion = "1.30.0"; DllName = "Azure.Core.dll" }, + @{ PackageName = "System.Memory.Data"; PackageVersion = "1.0.2"; DllName = "System.Memory.Data.dll" } + ) + + $svcPackages | ForEach-Object { + $packageName = $_["PackageName"] + $packageVersion = $_["PackageVersion"] + $packageDll = $_["DllName"] + Install-Package -Name $packageName -RequiredVersion $packageVersion -Source "https://www.nuget.org/api/v2" -Destination $svcPackagesDir -SkipDependencies -ExcludeVersion -Force + Add-Type -LiteralPath (Join-Path -Path $svcPackagesDir -ChildPath $packageName | Join-Path -ChildPath "lib" | Join-Path -ChildPath "netstandard2.0" | Join-Path -ChildPath $packageDll) -ErrorAction SilentlyContinue + } +} + +function Send-EmailServiceMail { + param ( + [Parameter(Mandatory)] + [string] $To, + + [Parameter(Mandatory)] + [string] $Subject, + + [Parameter(Mandatory)] + $Body + ) + + $emailClient = [Azure.Communication.Email.EmailClient]::new($EmailServiceConnectionString) + + Write-Host "Sending email..." + $emailClient.SendAsync([Azure.WaitUntil]::Completed, $EmailFrom, $To, $Subject, $Body).GetAwaiter().GetResult() + Write-Host "Finished sending email." +} + +InitializeEmailServicePackages diff --git a/tools/TestFx/Utilities/KustoUtility.psd1 b/tools/TestFx/Utilities/KustoUtility.psd1 index 75b050fe57e4..3b8db18ecebd 100644 --- a/tools/TestFx/Utilities/KustoUtility.psd1 +++ b/tools/TestFx/Utilities/KustoUtility.psd1 @@ -74,7 +74,7 @@ # NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. - FunctionsToExport = 'Import-KustoDataFromCsv' + FunctionsToExport = 'Import-KustoDataFromCsv', 'Get-KustoQueryData' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() diff --git a/tools/TestFx/Utilities/KustoUtility.psm1 b/tools/TestFx/Utilities/KustoUtility.psm1 index 9ac2d0f3b4fa..343f33f52282 100644 --- a/tools/TestFx/Utilities/KustoUtility.psm1 +++ b/tools/TestFx/Utilities/KustoUtility.psm1 @@ -11,6 +11,28 @@ # limitations under the License. # ---------------------------------------------------------------------------------- +param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [guid] $ServicePrincipalTenantId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [guid] $ServicePrincipalId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $ServicePrincipalSecret, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $ClusterName, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $ClusterRegion +) + function InitializeKustoPackages { [CmdletBinding()] param () @@ -24,7 +46,7 @@ function InitializeKustoPackages { New-Item -Path . -Name $kustoPackagesDirectoryName -ItemType Directory -Force $kustoPackages = @( - @{ PackageName = "Azure.Core"; PackageVersion = "1.25.0"; DllName = "Azure.Core.dll" }, + @{ PackageName = "Azure.Core"; PackageVersion = "1.30.0"; DllName = "Azure.Core.dll" }, @{ PackageName = "Azure.Data.Tables"; PackageVersion = "12.6.1"; DllName = "Azure.Data.Tables.dll" }, @{ PackageName = "Azure.Storage.Blobs"; PackageVersion = "12.13.0"; DllName = "Azure.Storage.Blobs.dll" }, @{ PackageName = "Azure.Storage.Common"; PackageVersion = "12.12.0"; DllName = "Azure.Storage.Common.dll" }, @@ -44,33 +66,13 @@ function InitializeKustoPackages { $packageVersion = $_["PackageVersion"] $packageDll = $_["DllName"] Install-Package -Name $packageName -RequiredVersion $packageVersion -Source "https://www.nuget.org/api/v2" -Destination $kustoPackagesDirectory -SkipDependencies -ExcludeVersion -Force - Add-Type -LiteralPath (Join-Path -Path $kustoPackagesDirectory -ChildPath $packageName | Join-Path -ChildPath "lib" | Join-Path -ChildPath "netstandard2.0" | Join-Path -ChildPath $packageDll) + Add-Type -LiteralPath (Join-Path -Path $kustoPackagesDirectory -ChildPath $packageName | Join-Path -ChildPath "lib" | Join-Path -ChildPath "netstandard2.0" | Join-Path -ChildPath $packageDll) -ErrorAction SilentlyContinue } } function Import-KustoDataFromCsv { [CmdletBinding()] param ( - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [guid] $ServicePrincipalTenantId, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [guid] $ServicePrincipalId, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServicePrincipalSecret, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ClusterName, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ClusterRegion, - [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $DatabaseName, @@ -137,4 +139,34 @@ function IngestDataFromCsv { } } +function Get-KustoQueryData { + param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $DatabaseName, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $Query + ) + + $queryUri = "https://$ClusterName.$ClusterRegion.kusto.windows.net" + $queryBuilder = [Kusto.Data.KustoConnectionStringBuilder]::new($queryUri).WithAadApplicationKeyAuthentication($ServicePrincipalId, $ServicePrincipalSecret, $ServicePrincipalTenantId.ToString()) + $queryClient = [Kusto.Data.Net.Client.KustoClientFactory]::CreateCslQueryProvider($queryBuilder) + $queryResult = $queryClient.ExecuteQuery($DatabaseName, $Query, $null) + $results = @() + while ($queryResult.Read()) { + $resultObj = [PSCustomObject]@{} + for ($i = 0; $i -lt $queryResult.FieldCount; $i ++) { + $propName = $queryResult.GetName($i) + $propValue = $queryResult.GetValue($i) + + $resultObj | Add-Member -NotePropertyName $propName -NotePropertyValue $propValue + } + $results += $resultObj + } + + $results +} + InitializeKustoPackages