Azure pipelines: How to add failed selenium Xunit test case attachment in VS test task - selenium

I use the Xunit2 selenium framework for automated test cases. Some case fails in pipeline. I want to see the attachment of the fail test case in the Test tab. How can I do this using VS test task?

The option publishRunAttachments: true, it will update attachments to Test run attachment tab, check the pic below
After the VS test task runs, we can get the run ID through the variable VSTEST_TESTRUNID.
Then we could call the RESST API Create Test Result Attachment to add attachments to the test result attachment tab.
Request API:
POST https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/attachments?api-version=6.0-preview.1
Request Body:
{
"stream": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABlSURBVDhP7cxBCsAgDERR739pG/CnGJI0FopQ8O2cjNP6R85QbeNQU7wT1dkijaQ3vkZoWElaoTeJojW01cYh0jwfgiFBV/lEjOZtacijN/nLkOBHhIaVDgn+Wdycp6FXzlCl9wt0Y0cAzHo/zgAAAABJRU5ErkJggg==",
"fileName": "imageAsFileAttachment.png",
"comment": "Test attachment upload",
"attachmentType": "GeneralAttachment"
}
You could also check this thread
Update1
We could add task power shell and call the rest api via below script:
$connectionToken="{PAT}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$URL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/attachments?api-version=6.0-preview.1"
$body =#"
{
"stream": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABlSURBVDhP7cxBCsAgDERR739pG/CnGJI0FopQ8O2cjNP6R85QbeNQU7wT1dkijaQ3vkZoWElaoTeJojW01cYh0jwfgiFBV/lEjOZtacijN/nLkOBHhIaVDgn+Wdycp6FXzlCl9wt0Y0cAzHo/zgAAAABJRU5ErkJggg==",
"fileName": "imageAsFileAttachment.png",
"comment": "Test attachment upload",
"attachmentType": "GeneralAttachment"
}
"#
$Result = Invoke-RestMethod -Uri $URL -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
Update2
Check the pic below and notice the URL
According to the screenshot you shared before, it seems that you want to add attachments to the test run instead of test result. So we just need test run ID and we could get the test run ID from variable after the task vs test ends.
If you want to add attachments to test result, we could list all test result via test run ID.
Sample URL:
GET https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{RunID}/results
The add attachments to the test result via test result ID and test run ID.
Sample power shell script to list all test result ID
$connectionToken="{PAT}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$URL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{RunID}/results"
$Result = Invoke-RestMethod -Uri $URL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get
foreach($Run in $Result.value){
Write-Host "This test run contain" $Run.id "and the test reuslt name is" $Run.testCase.name
}
Update3
$connectionToken="{PAT}"
$base64AuthInfo= [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($connectionToken)"))
$URL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/134/results"
$Result = Invoke-RestMethod -Uri $URL -Headers #{authorization = "Basic $base64AuthInfo"} -Method Get
#List all test result get the test result ID via result
foreach($Run in $Result.value){
#Get the test result ID via result
If($Run.outcome -eq "Failed"){
$TestResultID = $Run.id
#Write-Host $TestResultID
#Add attachment via test run ID and test result ID
$TestResultAttachmentURL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/{runId}/Results/$($TestResultID)/attachments?api-version=6.0-preview.1"
$body =#"
{
"stream": "VXNlciB0ZXh0IGNvbnRlbnQgdG8gdXBsb2FkLg==",
"fileName": "textAsFileAttachment.txt",
"comment": "Test attachment upload",
"attachmentType": "GeneralAttachment"
}
"#
$TestResultAttachmentResult = Invoke-RestMethod -Uri $TestResultAttachmentURL -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
}
}
Update4
$AzureDevOpsPAT = {PAT}
$AzureDevOpsAuthenicationHeader = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($AzureDevOpsPAT)")) }
$UriOrga = "https://dev.azure.com/{organization}/{project}/"
$uriAccount = $UriOrga + "_apis/test/runs?api-version=6.0"
$response = Invoke-RestMethod -Uri $uriAccount -Headers $AzureDevOpsAuthenicationHeader -Method Get
$testRunsIdSorted = $response.value | sort-object id -Descending
Write-Host "##vso[task.setvariable variable=runId]$($testRunsIdSorted[0].id | ConvertTo-Json -Depth 100)"
$result = Invoke-RestMethod -Uri https://dev.azure.com/{organization}/{project}/_apis/test/runs/$($testRunsIdSorted[0].id)/results?api-version=6.0 -Headers $AzureDevOpsAuthenicationHeader -Method Get
#List all test result get the test result ID via result
foreach($Run in $result.value){
#Get the test result ID via result
If($Run.outcome -eq "Failed"){
$TestResultID = $Run.id
#Write-Host $TestResultID
#Add attachment via test run ID and test result ID
$TestResultAttachmentURL = "https://dev.azure.com/{organization}/{project}/_apis/test/Runs/$($runId)/Results/$($TestResultID)/attachments?api-version=6.0-preview.1"
$body =#"
{
"stream": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABlSURBVDhP7cxBCsAgDERR739pG/CnGJI0FopQ8O2cjNP6R85QbeNQU7wT1dkijaQ3vkZoWElaoTeJojW01cYh0jwfgiFBV/lEjOZtacijN/nLkOBHhIaVDgn+Wdycp6FXzlCl9wt0Y0cAzHo/zgAAAABJRU5ErkJggg==",
"fileName": "imageAsFileAttachment.png",
"comment": "Test attachment upload",
"attachmentType": "GeneralAttachment"
}
"#
$TestResultAttachmentResult = Invoke-RestMethod -Uri $TestResultAttachmentURL -ContentType "application/json" -Body $body -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST
}
}
If I click on .png file, it shows nothing.

Related

how to pass performance counters to SCOM Retrieve Performance Data Rest API?

I'm trying SCOM Retrieve Performance Data Rest API but I'm unable to pass performance counters as it's unclear in their official documentation.
https://learn.microsoft.com/en-us/rest/api/operationsmanager/data/retrieve%20performance%20data
Example :-
## Get performances for the given server
$myObject = [PSCustomObject]#{
objectname = 'Memory'
countername = 'Available MBytes'
}
$uriPerf = "http://$MS/OperationsManager/data/performance"
$perfFilter = #"
{
"duration": 100,
"id": "103c21b9-1dd1-e6ff-ede8-1091e0111abc",
"peformanceCounters":[$myObject]
}"#
$PerfResponse = Invoke-WebRequest `
-Method POST `
-Uri $uriPerf `
-Body $perfFilter `
-Headers $scomHeaders `
-Credential $cred `
-WebSession $websession `
#-AllowUnencryptedAuthentication
$perf = ConvertFrom-Json -InputObject $PerfResponse.Content
Write-Host "Timestamp after get all get performance data for $($server.id) call $(Get-Date)"
Write-Host "----------------"
This is the error I'm getting
Invoke-WebRequest : {"errorMessage":"Passed parameter cannot be null","errorTrace":""}

Can I mass-update VSTS build pipeline definitions?

I'm in the process of migrating from an on-premise TFS instance to VSTS. I have a lot of build pipelines (vNext build definitions) that were migrated to VSTS, but now I have to update them all to use a specific Agent.
There is no option available in the UI nor in the commandline client.
Am I missing an option available to me so I can update them all at once?
Based on the migration work I did with Manuel (referred to the post Jesse mentions), I have made some scripts available that get the TFS queues and then use that for updating the VSTS build definitions.
Read-QueuesFromTfs.ps1
Repair-BuildDefinitions.ps1
Both scripts require a parameters PersonalAccesToken - One is a PAT for the VSTS account you are targeting and one for targeting the TFS environment.
First script helps you get a queues.json file that holds all TFS Queues. Second script iterates the VSTS projects you are targeting for updating the build definitions. Scripts should be quite self-explanatory.
# Get all queues and based on previous names get the id's
(Invoke-RestMethod `
-Uri "https://$account.visualstudio.com/$_/_apis/distributedtask/queues" `
-Headers #{Authorization = "Basic $auth"; Accept = "application/json; api-version=3.2-preview" } `
-Method Get `
-ContentType "application/json" -Verbose).value | % { $vstsqueues[$_.name] = $_.id }
# get all the builds
$builds = (Invoke-RestMethod `
-Uri "https://$account.visualstudio.com/$_/_apis/build/definitions" `
-Headers #{Authorization = "Basic $auth"; Accept = "application/json; api-version=4.1-preview.6" } `
-Method Get `
-ContentType "application/json").value
# get the full build definition
$build = Invoke-RestMethod `
-Uri $_.url `
-Headers #{Authorization = "Basic $auth"; Accept = "application/json; api-version=4.1-preview.6" } `
-Method Get `
-ContentType "application/json"
# get queue
$queuename = $tfsqueues[$_.queue.id]
Write-Output " queue name: $queuename"
# update build
$build.queue = #{ id = $vstsqueues[$queuename] }
# post changes
Invoke-RestMethod `
-Uri $_.url `
-Headers #{Authorization = "Basic $auth"; Accept = "application/json; api-version=4.1-preview.6" } `
-Method Put `
-ContentType "application/json" `
-Body ($build | ConvertTo-Json -Depth 100 -Compress) | Out-Null
}
}
Described in this file. https://github.com/JasperGilhuis/VSTS-RestAPI/blob/master/README.md#update-vsts-build-definitions-based-on-tfs-queues
Look that the Builds folder in the repository https://github.com/JasperGilhuis/VSTS-RestAPI/tree/master/Builds

Powershell Rest API- Encode PDF to B64

I'm having an issue trying to get this to work. What I'm trying to do is upload a "PDF" to our system using API commands in Powershell. I've been able to upload "documents" from my disk drive, but when I try to view them they are either "Document not found" or "Cannot open this PDF" or ""The input is not a valid Base-64 string as it contains a non-base 64 character". I've tried different methods: encoding/decoding in a variety of ways, I've tried opening it in several different programs- doesn't seem like nothing is working and I'm losing sleep.
Below is my code for just straight upload:
$fileName = "C:\files\Test1.pdf"
$data = ConvertTo-Json #{
encrypted="false";
allowSaveBinaryData="True";
binaryData=$fileName;
divider="Expense Report";
isMultipageImage="true";
extension="pdf";
name="Test1.pdf";
relProjectId="31";
}
$addproject="https://ENDPOINT URL.com/v4/documents/597?guid=$temp&fbsite=https://MYURL.com/"
Invoke-RestMethod -ContentType 'application/json' -Method PUT -Body $data -Uri $addproject
Below is my code I tried using encoding/decoding:
$fileName = "C:\files\Test1.pdf"
$fileContent = get-content $fileName
$fileContentBytes = [System.Text.Encoding]::Unicode.GetBytes($fileContent)
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
$data = ConvertTo-Json #{
encrypted="false";
allowSaveBinaryData="True";
binaryData=$fileContentEncoded;
divider="Expense Report";
isMultipageImage="true";
extension="pdf";
name="Test1.pdf";
relProjectId="31";
}
$addproject="https://ENDPOINT URL.com/v4/documents/597?guid=$temp&fbsite=https://MYURL.com/"
Invoke-RestMethod -ContentType 'application/json' -Method PUT -Body $data -Uri $addproject
I've figured it out with this::
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", 'application/pdf')
$fileName="C:\files\$item2"
$fileContent = get-content -Raw $fileName
$fileContentBytes = [System.Text.Encoding]::Default.GetBytes($fileContent)
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
$data = ConvertTo-Json #{
encrypted="false";
allowSaveBinaryData="true";
binaryData="$fileContentEncoded"
divider="Expense Report";
extension="pdf";
name="$fileContentEncoded";
relProjectId="31";
fileID="597"
}
$var2[$i2]="https://MY ENDPOINT /v4/documents/597?guid=$AUTHtemp&fbsite=https://XXXXXXXXX/"
Invoke-RestMethod -headers $headers -ContentType 'application/json' -Method PUT -body $data -Uri $var2[$i2]}

API: Trying to set name of an appveyor project

I am trying to create an appveyor project using powershell and set my own name.
function Invoke-AppveyorCreateProject {
param (
[System.String] $appveyorProjectName,
[System.String] $repositoryName
)
# step 1, create project
$project = #{
repositoryProvider="gitHub"
repositoryName="esskar/$repositoryName"
isPrivate=$true
}
$json = $project | ConvertTo-Json
$project = Invoke-RestMethod -Method Post -Uri "$AppveyorApiUrl/projects" -Headers $AppveyorRestHeaders -Body $json -ContentType "application/json"
# step 2, update project
$project.name = $appveyorProjectName
$json = $project | ConvertTo-Json
$project = Invoke-RestMethod -Method Put -Uri "$AppveyorApiUrl/projects" -Headers $AppveyorRestHeaders -Body $json -ContentType "application/json"
}
# Globals
$AppveyorApiUrl = 'https://ci.appveyor.com/api'
$AppveyorApiToken = $env:AppveyorApiToken
$AppveyorRestHeaders = #{
"Authorization" = "Bearer $AppveyorApiToken"
"Content-type" = "application/json"
}
$AppveyorAccountName = $env:AppveyorAccountName
Invoke-AppveyorCreateProject "foo.bar" "repo1"
Step 1 works, the project is created, but when I try to change the name, i get an exception
Invoke-RestMethod : {"message":"Object reference not set to an instance of an object."}
At appveyortest.ps1:20 char:16
+ ... $project = Invoke-RestMethod -Method Put -Uri "$AppveyorApiUrl/proje ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
when i try to set the name during creation in step 1, then name is not used, and project has the same name as without setting the name.
Use the following code for the Step 2:
$settings = Invoke-RestMethod -Uri "$AppveyorApiUrl/projects/$($project.accountName)/$($project.slug)/settings" -Headers $AppveyorRestHeaders -Method Get
$settings.settings.name = $appveyorProjectName
Invoke-RestMethod -Uri "$AppveyorApiUrl/projects" -Headers $AppveyorRestHeaders -Body ($settings.settings | ConvertTo-Json -Depth 10) -Method Put

TFS2015 REST API Build definition update

I'm trying to update a build definition through REST API with PowerShell.
The script used is:
$url = "http://tfs:8080/tfs/collection/project/_apis/build/definitions/$($buildId)?api-version=2.0"
$obj = Invoke-RestMethod -Uri $url2 -Method Get -ContentType "application/json" -UseDefaultCredentials
$json = ConvertTo-Json $obj
Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -UseDefaultCredentials
First I've tried with a new empty definition and I've got the below error:
The collection must contain at least one element.Parameter name:
definition.Options.Inputs
So I added an extra code to remove the "options" part from the returned json:
if($obj.options -ne $null){
$obj.options = $null }
and the update worked. But when I'm using the code on an "real" existing build definition that is in production then I get another error:
The collection must contain at least one element.
Parameter name: definition.RetentionRules.Rule.Branches.Filter
I'm using TFS2015 Update 3.
Why is not working a simple update (without any modification) of a build definition via REST API?
The line $json = ConvertTo-Json $obj needs changed to include the -Depth argument with a minimum value of 3. The default is 2 and because of the nesting the values are lost when converted from an object to Json. More specifically what happens is the values get converted from an array to a simple string.
How to tell this is happening in the Json
Without the depth parameter
"retentionRules": [
{
"branches": "+refs/heads/*",
"artifacts": "build.SourceLabel",
"daysToKeep": 10,
"minimumToKeep": 1,
"deleteBuildRecord": true,
"deleteTestResults": true
}
]
With the depth parameter
"retentionRules": [
{
"branches": [
"+refs/heads/*"
],
"artifacts": [
"build.SourceLabel"
],
"daysToKeep": 10,
"minimumToKeep": 1,
"deleteBuildRecord": true,
"deleteTestResults": true
}
]
You will see that the the branches and artifacts values change from a string to an array with the proper depth value.
What your example code should be
$url = "http://tfs:8080/tfs/collection/project/_apis/build/definitions/$($buildId)?api-version=2.0"
$obj = Invoke-RestMethod -Uri $url2 -Method Get -ContentType "application/json" -UseDefaultCredentials
$json = ConvertTo-Json $obj -Depth 3
Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -UseDefaultCredentials