diff --git a/Tasks/QuickPerfTest/CltTasksUtility.ps1 b/Tasks/QuickPerfTest/CltTasksUtility.ps1
new file mode 100644
index 000000000000..8f5dd4175666
--- /dev/null
+++ b/Tasks/QuickPerfTest/CltTasksUtility.ps1
@@ -0,0 +1,191 @@
+function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body)
+{
+ $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri)
+ $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $global:userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body
+ $ServicePoint.CloseConnectionGroup("")
+ return $result
+}
+
+function ComposeTestDropJson($name, $duration, $homepage, $vu, $geoLocation)
+{
+ $tdjson = @"
+ {
+ "dropType": "InplaceDrop",
+ "loadTestDefinition":{
+ "loadTestName":"$name",
+ "runDuration":$duration,
+ "urls":["$homepage"],
+ "browserMixs":[
+ {"browserName":"Internet Explorer 11.0","browserPercentage":60.0},
+ {"browserName":"Chrome 2","browserPercentage":40.0}
+ ],
+ "loadPatternName":"Constant",
+ "maxVusers":$vu,
+ "loadGenerationGeoLocations":[
+ {"Location":"$geoLocation","Percentage":100}
+ ]
+ }
+ }
+"@
+
+ return $tdjson
+}
+
+function CreateTestDrop($headers, $dropJson, $CltAccountUrl)
+{
+ $uri = [String]::Format("{0}/_apis/clt/testdrops?api-version=1.0", $CltAccountUrl)
+ $drop = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $dropJson
+
+ return $drop
+}
+
+function GetTestDrop($headers, $drop, $CltAccountUrl)
+{
+ $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?api-version=1.0", $CltAccountUrl, $drop.id)
+ $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+
+ return $testdrop
+}
+
+function UploadTestDrop($testdrop)
+{
+ $uri = New-Object System.Uri($testdrop.accessData.dropContainerUrl)
+ $sas = New-Object Microsoft.WindowsAzure.Storage.Auth.StorageCredentials($testdrop.accessData.sasKey)
+ $container = New-Object Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer($uri, $sas)
+
+ return $container
+}
+
+#function GetTestRuns($headers, $CltAccountUrl)
+#{
+# $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl)
+# $runs = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+
+# return $runs
+#}
+
+function GetTestRunUri($testRunId, $headers, $CltAccountUrl)
+{
+ $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl,$testRunId)
+ $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+
+ return $run.WebResultUrl
+}
+
+function RunInProgress($run)
+{
+ return $run.state -eq "queued" -or $run.state -eq "inProgress"
+}
+
+function MonitorTestRun($headers, $run, $CltAccountUrl)
+{
+ $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id)
+ $prevState = $run.state
+ $prevSubState = $run.subState
+ Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState)
+
+ do
+ {
+ Start-Sleep -s 15
+ $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+ if ($prevState -ne $run.state -or $prevSubState -ne $run.subState)
+ {
+ $prevState = $run.state
+ $prevSubState = $run.subState
+ Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState)
+ }
+ }
+ while (RunInProgress $run)
+
+ $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+ Write-Output "------------------------------------"
+ $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?api-version=1.0", $CltAccountUrl, $run.id)
+ $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+
+ if ($messages)
+ {
+ $timeSorted = $messages.value | Sort-Object loggedDate
+ foreach ($message in $timeSorted)
+ {
+ switch ($message.messageType)
+ {
+ "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) }
+ "output" { Write-Host -NoNewline ("[Output]{0}" -f $message.message) }
+ "warning" { Write-Warning $message.message }
+ "error" { Write-Error $message.message }
+ "critical" { Write-Error $message.message }
+ }
+ }
+ }
+
+ Write-Output "------------------------------------"
+}
+
+function ComposeTestRunJson($name, $tdid, $machineType)
+{
+ $trjson = @"
+ {
+ "name":"$name",
+ "description":"Quick perf test from automation task",
+ "testSettings":{"cleanupCommand":"", "hostProcessPlatform":"x64", "setupCommand":""},
+ "superSedeRunSettings":{"loadGeneratorMachinesType":"$machineType"},
+ "testDrop":{"id":"$tdid"},
+ "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID"
+ }
+"@
+
+ return $trjson
+}
+
+function QueueTestRun($headers, $runJson, $CltAccountUrl)
+{
+ $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl)
+ $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson
+
+ $start = @"
+ {
+ "state": "queued"
+ }
+"@
+
+ $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id)
+ InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start
+ $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
+
+ return $run
+}
+
+function ComposeAccountUrl($connectedServiceUrl, $headers)
+{
+ #Load all dependent files for execution
+ . $PSScriptRoot/VssConnectionHelper.ps1
+ $connectedServiceUrl = $connectedServiceUrl.TrimEnd('/')
+ Write-Host "Getting Clt Endpoint:"
+ $elsUrl = Get-CltEndpoint $connectedServiceUrl $headers
+
+ return $elsUrl
+}
+
+function ValidateInputs($websiteUrl, $tfsCollectionUrl, $connectedServiceName)
+{
+ if (![System.Uri]::IsWellFormedUriString($websiteUrl, [System.UriKind]::Absolute))
+ {
+ throw "Website Url is not well formed."
+ }
+
+ if([string]::IsNullOrWhiteSpace($connectedServiceName) -and $tfsCollectionUrl -notlike "*VISUALSTUDIO.COM*" -and $tfsCollectionUrl -notlike "*TFSALLIN.NET*")
+ {
+ throw "VS Team Services Connection is mandatory for non hosted TFS builds "
+ }
+}
+
+function UploadSummaryMdReport($summaryMdPath)
+{
+ Write-Verbose "Summary Markdown Path = $summaryMdPath"
+
+ if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath)))
+ {
+ Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath"
+ }
+}
+
diff --git a/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1 b/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1
index 880b32e84bec..d6d3289fad50 100644
--- a/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1
+++ b/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1
@@ -6,7 +6,7 @@ param
[String]
$env:BUILD_BUILDID,
- [String] [Parameter(Mandatory = $true)]
+ [String] [Parameter(Mandatory = $false)]
$connectedServiceName,
[String] [Parameter(Mandatory = $true)]
@@ -23,212 +23,30 @@ param
$machineType
)
-$userAgent = "QuickPerfTestBuildTask"
-
-$global:RestTimeout = 60
-
function InitializeRestHeaders()
{
$restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]"
-
- $alternateCreds = [String]::Concat($Username, ":", $Password)
- $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds))
- $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth))
-
- return $restHeaders
-}
-
-function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body)
-{
- $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri)
- $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body
- $ServicePoint.CloseConnectionGroup("")
- return $result
-}
-
-function ComposeTestDropJson($name, $duration, $homepage, $vu)
-{
-$tdjson = @"
-{
- "dropType": "InplaceDrop",
- "loadTestDefinition":{
- "loadTestName":"$name",
- "runDuration":$duration,
- "urls":["$homepage"],
- "browserMixs":[
- {"browserName":"Internet Explorer 11.0","browserPercentage":60.0},
- {"browserName":"Chrome 2","browserPercentage":40.0}
- ],
- "loadPatternName":"Constant",
- "maxVusers":$vu,
- "loadGenerationGeoLocations":[
- {"Location":"$geoLocation","Percentage":100}
- ]
- }
-}
-"@
-
- return $tdjson
-}
-
-function CreateTestDrop($headers, $dropJson)
-{
- $uri = [String]::Format("{0}/_apis/clt/testdrops?api-version=1.0", $CltAccountUrl)
- $drop = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $dropJson
-
- return $drop
-}
-
-function GetTestDrop($headers, $drop)
-{
- $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?api-version=1.0", $CltAccountUrl, $drop.id)
- $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
-
- return $testdrop
-}
-
-function UploadTestDrop($testdrop)
-{
- $uri = New-Object System.Uri($testdrop.accessData.dropContainerUrl)
- $sas = New-Object Microsoft.WindowsAzure.Storage.Auth.StorageCredentials($testdrop.accessData.sasKey)
- $container = New-Object Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer($uri, $sas)
-
- return $container
-}
-
-function GetTestRuns($headers)
-{
- $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl)
- $runs = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
-
- return $runs
-}
-
-function GetTestRunUri($testRunId, $headers)
-{
- $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl,$testRunId)
- $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
-
- return $run.WebResultUrl
-}
-
-function RunInProgress($run)
-{
- return $run.state -eq "queued" -or $run.state -eq "inProgress"
-}
-
-function MonitorTestRun($headers, $run)
-{
- $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id)
- $prevState = $run.state
- $prevSubState = $run.subState
- Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState)
-
- do
- {
- Start-Sleep -s 5
- $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
- if ($prevState -ne $run.state -or $prevSubState -ne $run.subState)
- {
- $prevState = $run.state
- $prevSubState = $run.subState
- Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState)
- }
- }
- while (RunInProgress $run)
-
- $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
- Write-Output "------------------------------------"
- $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?api-version=1.0", $CltAccountUrl, $run.id)
- $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
-
- if ($messages)
- {
- $timeSorted = $messages.value | Sort-Object loggedDate
- foreach ($message in $timeSorted)
- {
- switch ($message.messageType)
- {
- "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) }
- "output" { Write-Host -NoNewline ("[Output]{0}" -f $message.message) }
- "warning" { Write-Warning $message.message }
- "error" { Write-Error $message.message }
- "critical" { Write-Error $message.message }
- }
- }
+ if([string]::IsNullOrWhiteSpace($connectedServiceName))
+ {
+ $restHeaders.Add("Authorization", [String]::Concat("Bearer ", $env:SYSTEM_ACCESSTOKEN))
+
}
-
- Write-Output "------------------------------------"
-}
-
-function ComposeTestRunJson($name, $tdid)
-{
-$trjson = @"
-{
- "name":"$name",
- "description":"Quick perf test from automation task",
- "testSettings":{"cleanupCommand":"", "hostProcessPlatform":"x86", "setupCommand":""},
- "superSedeRunSettings":{"loadGeneratorMachinesType":"$MachineType"},
- "testDrop":{"id":"$tdid"},
- "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID"
-}
-"@
-
- return $trjson
-}
-
-function QueueTestRun($headers, $runJson)
-{
- $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl)
- $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson
-
-$start = @"
-{
- "state": "queued"
-}
-"@
-
- $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id)
- InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start
- $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers
-
- return $run
-}
-
-function ComposeAccountUrl($vsoUrl)
-{
- $elsUrl = $vsoUrl
-
- if ($vsoUrl -notlike "*VSCLT.VISUALSTUDIO.COM*")
- {
- if ($vsoUrl -like "*VISUALSTUDIO.COM*")
- {
- $accountName = $vsoUrl.Split('//')[2].Split('.')[0]
- $elsUrl = ("https://{0}.vsclt.visualstudio.com" -f $accountName)
- }
- }
-
- return $elsUrl
-}
-
-function ValidateInputs()
-{
- if (![System.Uri]::IsWellFormedUriString($websiteUrl, [System.UriKind]::Absolute))
- {
- throw "Website Url is not well formed."
- }
-}
-
-function UploadSummaryMdReport($summaryMdPath)
-{
- Write-Verbose "Summary Markdown Path = $summaryMdPath"
-
- if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath)))
- {
- Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath"
+ else
+ {
+ $alternateCreds = [String]::Concat($Username, ":", $Password)
+ $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds))
+ $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth))
}
+ return $restHeaders
}
+ # Load all dependent files for execution
+ . $PSScriptRoot/CltTasksUtility.ps1
+ . $PSScriptRoot/VssConnectionHelper.ps1
+
+$userAgent = "QuickPerfTestBuildTask"
+$global:RestTimeout = 60
+
############################################## PS Script execution starts here ##########################################
Write-Output "Starting Quick Perf Test Script"
@@ -245,47 +63,53 @@ Write-Output "Load generator machine type = $machineType"
Write-Output "Run source identifier = build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID"
#Validate Input
-ValidateInputs
-
-$connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName
+ValidateInputs $websiteUrl $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI $connectedServiceName
+if([string]::IsNullOrWhiteSpace($connectedServiceName))
+{
+ $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name SystemVssConnection
+}
+else
+{
+ $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName
+}
$Username = $connectedServiceDetails.Authorization.Parameters.Username
Write-Verbose "Username = $Username" -Verbose
$Password = $connectedServiceDetails.Authorization.Parameters.Password
$VSOAccountUrl = $connectedServiceDetails.Url.AbsoluteUri
-$CltAccountUrl = ComposeAccountUrl($VSOAccountUrl).TrimEnd('/')
+Write-Output "VSO Account URL is : $VSOAccountUrl"
+$headers = InitializeRestHeaders
+$CltAccountUrl = ComposeAccountUrl $VSOAccountUrl $headers
$TFSAccountUrl = $env:System_TeamFoundationCollectionUri.TrimEnd('/')
-Write-Verbose "VSO account Url = $TFSAccountUrl" -Verbose
-Write-Verbose "CLT account Url = $CltAccountUrl" -Verbose
+Write-Output "VSO account Url = $TFSAccountUrl" -Verbose
+Write-Output "CLT account Url = $CltAccountUrl" -Verbose
-$headers = InitializeRestHeaders
-$dropjson = ComposeTestDropJson $testName $runDuration $websiteUrl $vuLoad
-$drop = CreateTestDrop $headers $dropjson
+
+$dropjson = ComposeTestDropJson $testName $runDuration $websiteUrl $vuLoad $geoLocation
+
+$drop = CreateTestDrop $headers $dropjson $CltAccountUrl
+
if ($drop.dropType -eq "InPlaceDrop")
{
- $runJson = ComposeTestRunJson $testName $drop.id
-
- $run = QueueTestRun $headers $runJson
- MonitorTestRun $headers $run
- $webResultsUrl = GetTestRunUri $run.id $headers
+ $runJson = ComposeTestRunJson $testName $drop.id $MachineType
+ $run = QueueTestRun $headers $runJson $CltAccountUrl
+ MonitorTestRun $headers $run $CltAccountUrl
+ $webResultsUrl = GetTestRunUri $run.id $headers $CltAccountUrl
Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name)
Write-Output ("To view run details navigate to {0}" -f $webResultsUrl)
Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run."
- $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary"
-
+ $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary"
$resultFilePattern = ("QuickPerfTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID)
-
$excludeFilePattern = ("QuickPerfTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID)
Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force
$summaryFile = ("{0}\QuickPerfTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id)
-
$summary = ('[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUrl ,$run.name)
- ('
{0}
' -f $summary) | Out-File $summaryFile -Encoding ascii -Append + ('{0}
' -f $summary) >> $summaryFile UploadSummaryMdReport $summaryFile } else diff --git a/Tasks/QuickPerfTest/VssConnectionHelper.ps1 b/Tasks/QuickPerfTest/VssConnectionHelper.ps1 new file mode 100644 index 000000000000..1365d4e155c8 --- /dev/null +++ b/Tasks/QuickPerfTest/VssConnectionHelper.ps1 @@ -0,0 +1,41 @@ +function Get-CltEndpoint($connectedServiceUrl, $headers) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $vsoUrl = $connectedServiceUrl + Write-Host "Fetching the Clt endpoint for $vsoUrl" + $spsLocation = Get-SpsLocation $vsoUrl $headers + $cltLocation = Get-CltLocation $spsLocation $headers + + return $cltLocation + +} + +function Get-SpsLocation($vsoUrl, $headers) +{ + Write-Host "Fetching the SPS endpoint for $vsoUrl" + $spsUniqueIdentifier = "951917AC-A960-4999-8464-E3F0AA25B381" + $spsLocation = Get-ServiceLocation $vsoUrl $headers $spsUniqueIdentifier + return $spsLocation +} + +function Get-CltLocation($spsUrl, $headers) +{ + Write-Host "Fetching the CLT endpoint for $vsoUrl" + $cltUniqueIdentifier = "6C404D78-EF65-4E65-8B6A-DF19D6361EAE" + return Get-ServiceLocation $spsUrl $headers $cltUniqueIdentifier +} + +function Get-ServiceLocation($baseUrl, $headers, $serviceUniqueIdentifier) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $locationCallUri = [string]::Format("{0}/_apis/servicedefinitions/LocationService2/{1}", $baseUrl, $serviceUniqueIdentifier) + $locationCallJsonResponse = InvokeRestMethod -Uri $locationCallUri -contentType "application/json" -headers $headers -Method Get + if($locationCallJsonResponse) + { + return $locationCallJsonResponse.locationMappings.location|Select -First 1 + } + + return $null +} \ No newline at end of file diff --git a/Tasks/QuickPerfTest/task.json b/Tasks/QuickPerfTest/task.json index 1de0341df99c..be95cd6f0a49 100644 --- a/Tasks/QuickPerfTest/task.json +++ b/Tasks/QuickPerfTest/task.json @@ -13,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 13 + "Patch": 14 }, "demands": [ "msbuild", @@ -24,9 +24,8 @@ { "name": "connectedServiceName", "type": "connectedService:Generic", - "label": "Registered connection", + "label": "VS Team Services Connection", "defaultValue": "", - "required": true, "helpMarkDown": "Select a previously registered service connection to talk to the cloud-based load test service. Choose 'Manage' to register a new connection." }, {