Link TFS test run to a release via c# - c#

Using the new TFS api:
Microsoft.TeamFoundationServer. ExtendedClient
I have succeeded creating a test run and attaching a release and release environment to it so a link to the release appears at the test run summery.
However, when I go to the release page and click the "Tests" tab I cannot see the test run and it's statistics.
How can I "make" the release know the test run and add it to the release via c# code?
Here is my code:
// Creates a TFS test run
public static void CreateTestRun(ITestPlan testPlan, int testCaseId, string testResult,
string buildIdStr, string releaseUri, string releaseEnvironmentUri, string testRunName)
{
// --------------------------------Biuld the RunCreateModel for the test run:------------------------------------------------
// Find the test points of the current test case
List<int> testPointIds = new List<int>();
ITestPointCollection testPoints = testPlan.QueryTestPoints("SELECT * FROM TestPoint WHERE testPoint.TestCaseId='" + testCaseId + "'");
foreach (ITestPoint testPoint in testPoints)
{
testPointIds.Add(testPoint.Id);
}
int buildId;
int.TryParse(buildIdStr, out buildId);
// Init RunCreateModel:
RunCreateModel runCreateModel = new RunCreateModel(
name: testRunName,
startedDate: DateTime.Now.ToString("M/d/y h:m:s tt"),
plan: new ShallowReference(id: testPlan.Id.ToString()),
pointIds: testPointIds.ToArray(),
buildId: buildId,
releaseUri: releaseUri,
releaseEnvironmentUri: releaseEnvironmentUri
);
// ----------------------------------------------------------------------------------------------------------------------------
// -------------------------------------------------Create test run in progress--------------------------------------------
TestManagementHttpClient testManagementClient =
new TestManagementHttpClient(new Uri(TFS_COLLECTION_NAME), new VssCredentials());
// Use RunCreateModel to create a test run on TFS (using the extended API):
TestRun testRunExtended =
testManagementClient.CreateTestRunAsync(runCreateModel, TFS_TEAM_PROJECT_NAME).Result;
// ---------------------------------------------------------------------------------------------------------------------------
// Using the regular client api, add results to the test run to complete it:
TfsTeamProjectCollection tfsCollection = new TfsTeamProjectCollection(new Uri(TFS_COLLECTION_NAME), new VssCredentials());
ITestManagementService testManagement = tfsCollection.GetService<ITestManagementService>();
IEnumerable<ITestRun> testRuns = testManagement.QueryTestRuns(
"SELECT * FROM TestRun WHERE TestRunID='" + testRunExtended.Id + "'");
ITestRun testRun = testRuns.First();
// Update the outcome of the test
ITestCaseResultCollection results = testRun.QueryResults();
foreach (ITestCaseResult result in results)
{
result.Outcome = testResult == "Pass" ?
Microsoft.TeamFoundation.TestManagement.Client.TestOutcome.Passed :
Microsoft.TeamFoundation.TestManagement.Client.TestOutcome.Failed;
result.State = TestResultState.Completed;
result.Save();
}
testRun.Save();
testRun.Refresh();
}
Thx.

Solved by setting the RunCreateModel.isAutomated property to true.

You could use REST API to update test run by its ID, the api is as below:
PATCH https://{accountName}.visualstudio.com/{project}/_apis/test/runs/{runId}?api-version=5.0-preview.2
You need to modify or add the following part in the body:
"releaseUri": "vstfs:///ReleaseManagement/Release/{releaseID}",
"releaseEnvironmentUri": "vstfs:///ReleaseManagement/Environment/{releaseID}",
"release": {
"id": {releaseID},
"name": "{releaseName}",
"environmentId": {releaseID},
"environmentName": "{EnvironmentName}",
"definitionId": {definitionId},
"environmentDefinitionId": {definitionId},
"environmentDefinitionName": null,
"attempt": 1
},
I've tested on my side, it's working.

Related

C# dynamics throws RuntimeBinderException when accessing property

I'm getting a RuntimeBinderException when attempting to read a property from a dynamic object. This is no doubt one of those issues where I've not got the syntax quite right, but I'm just not seeing it....
Using a simple LinqPad script, the following works fine:
void Main()
{
var response = new
{
DotNet = Environment.Version,
ServerName = Environment.MachineName,
};
dynamic d = response;
var x = d.DotNet as Version;
x.Major.Dump();
}
If I return it from a Web Method, then I'm running into issues. Here is my simple web method (.Net 5 WebAPI)
public IActionResult GetEnvironmentDetails()
{
var response = new
{
DotNet = Environment.Version,
ServerName = Environment.MachineName,
};
return this.Ok(response);
}
In my unit test, I can read the property using reflection, but not using dynamics:
var c = new MyController();
var response = c.GetEnvironmentDetails() as OkObjectResult;
// This next line gets me the property using reflection:
Version dotNet = response.Value.GetType().GetProperty("DotNet").GetValue(response.Value, null) as Version;
// But...using dynamics
dynamic d = response.Value;
// then the following fails for me
object x = d.DotNet;
If I put the variable d in my WATCH window, then the Value shows as { DotNet = {5.0.4}, ServerName = "MyComputerName" } and the Type is <Anonymous Type>.

Attach screenshot to Test Step Result (ITestStepResult) - VSTS

I am able to create a new Test Run and update each Test Step status and finally complete the Automated Test RUN. I have used C# library files to do all these to VSTS.
Also I am currently working on attaching screenshot to the Test Step result. I can see that screenshot getting attached to the Test Step under Run tab but the upload was not complete and not able to see the screenshot getting loaded.
Following is the code used to attach screenshot:
ITestAttachment attachment = stepResult.CreateAttachment(screenShotPath);
stepResult.Attachments.Add(attachment);
Also please find the screenshot attached to understand my problem much better.
Thanks for the help in advance
With this code below, it uploads the attachment to test step, when I check the test result, the image isn’t displayed correctly (the same as you), but after a minute, it displays correctly. So, you can check image whether displays correctly now.
int testpointid = 56;
var u = new Uri("https://XXX.visualstudio.com");
var c = new VssClientCredentials();
c.Storage = new VssClientCredentialStorage(storageKind: "VssApp", storageNamespace: "VisualStudio");
TfsTeamProjectCollection _tfs = new TfsTeamProjectCollection(u, c);
_tfs.EnsureAuthenticated();
ITestManagementService test_service = (ITestManagementService)_tfs.GetService(typeof(ITestManagementService));
ITestManagementTeamProject _testproject = test_service.GetTeamProject("{proejct}");
ITestPlan _plan = _testproject.TestPlans.Find(89);
ITestRun testRun = _plan.CreateTestRun(false);
testRun.Title = "apiTest2";
ITestPoint point = _plan.FindTestPoint(testpointid);
testRun.AddTestPoint(point, test_service.AuthorizedIdentity);
testRun.Save();
testRun.Refresh();
ITestCaseResultCollection results = testRun.QueryResults();
ITestIterationResult iterationResult;
foreach (ITestCaseResult result in results)
{
iterationResult = result.CreateIteration(1);
foreach (Microsoft.TeamFoundation.TestManagement.Client.ITestStep testStep in result.GetTestCase().Actions)
{
ITestStepResult stepResult = iterationResult.CreateStepResult(testStep.Id);
stepResult.Outcome = Microsoft.TeamFoundation.TestManagement.Client.TestOutcome.Passed; //you can assign different states here
Microsoft.TeamFoundation.TestManagement.Client.ITestAttachment attachment = stepResult.CreateAttachment(#"{image path}");
stepResult.Attachments.Add(attachment);
iterationResult.Actions.Add(stepResult);
}
iterationResult.Outcome = Microsoft.TeamFoundation.TestManagement.Client.TestOutcome.Passed;
result.Iterations.Add(iterationResult);
result.Outcome = Microsoft.TeamFoundation.TestManagement.Client.TestOutcome.Passed;
result.State = TestResultState.Completed;
result.Save(true);
}
testRun.State = Microsoft.TeamFoundation.TestManagement.Client.TestRunState.Completed;
results.Save(true);

Extent Reports version 3.0.2 - AppendExisting

Below is the code I am trying to use to append all tests to a single report. However, latest test is replacing all the older test reports. So, it's not appending to a single report for some reason. Can you please help me out here?
var htmlReporter = new ExtentHtmlReporter(ResourcesConfig.ReportPath);
extent = new ExtentReports();
extent.AttachReporter(htmlReporter);
htmlReporter.LoadConfig(ResourcesConfig.ReportXMLPath);
**htmlReporter.AppendExisting = true;**
I had a lot of trouble with this as well as the documentation doesn't explain much. I have one method called ReportCreation which runs for every test case and in that method i have the following:
public static ExtentReports ReportCreation(){
System.out.println(extent);
if (extent == null) {
extent = new ExtentReports();
htmlReports = new ExtentHtmlReporter(fileName+ n + "\\extentReportFile.html");
htmlReports.config().setReportName("Pre release Smoke test");
htmlReports.config().setTheme(Theme.STANDARD);
htmlReports.config().setTestViewChartLocation(ChartLocation.BOTTOM);
extent.attachReporter(htmlReports);
}
else {
htmlReports = new ExtentHtmlReporter(fileName+ n+ "\\extentReportFile.html");
htmlReports.setAppendExisting(true);
extent.attachReporter(htmlReports);
}
return extent;
}
So when the first unit test is run, it will create the html report, but the second unit test will see that the report has already been generated and so use the existing one.
I have created a random number generator so that it goes to a different report on every run
public static Random rand = new Random();
public static int n = rand.nextInt(10000)+1;
I was facing the same issue. My solution was using .NET Core so ExtentReports 3 and 4 were not supported.
Instead, I wrote code to merge the results from previous html file to the new html file.
This is the code I used:
public static void GenerateReport()
{
// Publish test results to extentnew.html file
extent.Flush();
if (!File.Exists(extentConsolidated))
{
// Rename extentnew.html to extentconsolidated.html after execution of 1st batch
File.Move(extentLatest, extentConsolidated);
}
else
{
// Append test results to extentconsolidated.html from 2nd batch onwards
_ = AppendExtentHtml();
}
}
public static async Task AppendExtentHtml()
{
var htmlconsolidated = File.ReadAllText(extentConsolidated);
var htmlnew = File.ReadAllText(extentLatest);
var config = Configuration.Default;
var context = BrowsingContext.New(config);
var newdoc = await context.OpenAsync(req => req.Content(htmlnew));
var newlis = newdoc.QuerySelector(#"ul.test-list-item");
var consolidateddoc = await context.OpenAsync(req => req.Content(htmlconsolidated));
var consolidatedlis = consolidateddoc.QuerySelector(#"ul.test-list-item");
foreach (var li in newlis.Children)
{
li.RemoveFromParent();
consolidatedlis.AppendElement(li);
}
File.WriteAllText(extentConsolidated, consolidateddoc.DocumentElement.OuterHtml);
}
This logic bypasses any Extent Report reference and treats the result file as any other html.
Hope this helps.

C# / VBS Automate Team Project Creation in TFS 2015 Update 3

I'm looking for a way to automate team project creation in TFS 2015 Update 3.
I did a quick crawl over the web and found various posts on how to do it but nothing specific to 2015 version update 3.
Some links I found:
#1
#2
I'd like to do it as simple and lightweight as possible.
A rough idea would be to fill up all the details needed e.g.:
Sign in details, server, collection, project name, etc... on an excel, save the information somewhere (like an xml for presented on link#2) and trigger a batch file to do the necessary stuff via vbs macro.
To be honest I do not know where to start yet, like how to even automate the project creation part.
Appreciate if you can point me in the right path to start this out. Ideas are also welcome :). Thanks in advance!
You could use this REST API to create a team project. TFS also provide to using C# code to create a team project:
public static TeamProject CreateProject()
{
string projectName = "Sample project";
string projectDescription = "Short description for my new project";
string processName = "Agile";
VssCredentials c = new VssCredentials(new Microsoft.VisualStudio.Services.Common.WindowsCredential(new NetworkCredential("username", "password", "domain")));
VssConnection connection = new VssConnection(new Uri("http://v-tinmo-12r2:8080/tfs/MyCollection"),c);
// Setup version control properties
Dictionary<string, string> versionControlProperties = new Dictionary<string, string>();
versionControlProperties[TeamProjectCapabilitiesConstants.VersionControlCapabilityAttributeName] =
SourceControlTypes.Git.ToString();
// Setup process properties
ProcessHttpClient processClient = connection.GetClient<ProcessHttpClient>();
Guid processId = processClient.GetProcessesAsync().Result.Find(process => { return process.Name.Equals(processName, StringComparison.InvariantCultureIgnoreCase); }).Id;
Dictionary<string, string> processProperaties = new Dictionary<string, string>();
processProperaties[TeamProjectCapabilitiesConstants.ProcessTemplateCapabilityTemplateTypeIdAttributeName] =
processId.ToString();
// Construct capabilities dictionary
Dictionary<string, Dictionary<string, string>> capabilities = new Dictionary<string, Dictionary<string, string>>();
capabilities[TeamProjectCapabilitiesConstants.VersionControlCapabilityName] =
versionControlProperties;
capabilities[TeamProjectCapabilitiesConstants.ProcessTemplateCapabilityName] =
processProperaties;
//Construct object containing properties needed for creating the project
TeamProject projectCreateParameters = new TeamProject()
{
Name = projectName,
Description = projectDescription,
Capabilities = capabilities
};
// Get a client
ProjectHttpClient projectClient = connection.GetClient<ProjectHttpClient>();
TeamProject project = null;
try
{
Console.WriteLine("Queuing project creation...");
// Queue the project creation operation
// This returns an operation object that can be used to check the status of the creation
OperationReference operation = projectClient.QueueCreateProject(projectCreateParameters).Result;
// Check the operation status every 5 seconds (for up to 30 seconds)
Operation completedOperation = WaitForLongRunningOperation(connection, operation.Id, 5, 30).Result;
// Check if the operation succeeded (the project was created) or failed
if (completedOperation.Status == OperationStatus.Succeeded)
{
// Get the full details about the newly created project
project = projectClient.GetProject(
projectCreateParameters.Name,
includeCapabilities: true,
includeHistory: true).Result;
Console.WriteLine();
Console.WriteLine("Project created (ID: {0})", project.Id);
}
else
{
Console.WriteLine("Project creation operation failed: " + completedOperation.ResultMessage);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception during create project: ", ex.Message);
}
return project;
}
private static async Task<Operation> WaitForLongRunningOperation(VssConnection connection, Guid operationId, int interavalInSec = 5, int maxTimeInSeconds = 60, CancellationToken cancellationToken = default(CancellationToken))
{
OperationsHttpClient operationsClient = connection.GetClient<OperationsHttpClient>();
DateTime expiration = DateTime.Now.AddSeconds(maxTimeInSeconds);
int checkCount = 0;
while (true)
{
Console.WriteLine(" Checking status ({0})... ", (checkCount++));
Operation operation = await operationsClient.GetOperation(operationId, cancellationToken);
if (!operation.Completed)
{
Console.WriteLine(" Pausing {0} seconds", interavalInSec);
await Task.Delay(interavalInSec * 1000);
if (DateTime.Now > expiration)
{
throw new Exception(String.Format("Operation did not complete in {0} seconds.", maxTimeInSeconds));
}
}
else
{
return operation;
}
}
}

using libgit2sharp to pull latest from a branch

I am using libgit2sharp in a c# solution to switch to a branch and pull in the latest changes. Here is the code I am using:
public void FetchAll()
{
using (var repo = new Repository(_LocalGitPath))
{
foreach (Remote remote in repo.Network.Remotes)
{
FetchOptions options = new FetchOptions();
options.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
{
Username = _UserName,
Password = _Password
});
repo.Network.Fetch(remote, options);
}
}
}
public string CheckoutBranch(string branchName)
{
using (var repo = new Repository(_LocalGitPath))
{
var trackingBranch = repo.Branches[branchName];
if (trackingBranch.IsRemote)
{
branchName = branchName.Replace("origin/", string.Empty);
var branch = repo.CreateBranch(branchName, trackingBranch.Tip);
repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
Commands.Checkout(repo, branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
else
{
Commands.Checkout(repo, trackingBranch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
return branchName;
}
}
public void PullBranch(string branchName)
{
using (var repo = new Repository(_LocalGitPath))
{
PullOptions options = new PullOptions();
options.MergeOptions = new MergeOptions();
options.MergeOptions.FailOnConflict = true;
options.FetchOptions = new FetchOptions();
options.FetchOptions.CredentialsProvider = new CredentialsHandler((url, usernameFromUrl, types) => new UsernamePasswordCredentials()
{
Username = _UserName,
Password = _Password
});
repo.Network.Pull(new Signature(_UserName, _Password, new DateTimeOffset(DateTime.Now)), options);
}
}
I have no problem fetching, and checking out a branch. When I try to pull latest, I get an error saying, 'There is no tracking information for the current branch.' I believe that this means that the local branch doesn't know what the correct remote repository is to pull changes from, but I haven't been able to figure out how to tell libgit2sharp what the remote repo path is. Anyone have any suggestions?
While doing research on this problem I found this: https://github.com/libgit2/libgit2sharp/issues/1235. Essentially, a libgit2sharp dev describes the exact problem I am seeing, but doesn't provide any code for the fix.
One additional note: I will never be merging or pushing any changes back from this repository. I am pulling it for an automated build, so we can ignore or overwrite any local changes. I just need to get the latest code.
SOLUTION:
I have updated the code above with the solution that I got working. You need to be really careful to make sure that when you checkout a branch, you check the isRemote flag on the branch you are checking out is set to true. If you checkout a branch that isn't a remote it will set the remote to '.' in your git config file, and you need to manually fix it. If there isn't a valid remote you will not be able to pull the branch changes.
Do not use the code sample on the libgit2sharp wiki unless they add this check in.
You can setup the tracking brach information on the local branch by using the Refspec:
using (var repo = new Repository("/Users/sushi/code/redux/mono"))
{
var trackingBranch = repo.Branches["remotes/origin/work-btls"];
if (trackingBranch.IsRemote)
{
var branch = repo.CreateBranch("SomeLocalBranchName", trackingBranch.Tip);
repo.Branches.Update(branch, b => b.TrackedBranch = trackingBranch.CanonicalName);
repo.Checkout(branch, new CheckoutOptions { CheckoutModifiers = CheckoutModifiers.Force });
}
}
You can use git to verify that SomeLocalBranchName is now tracking remotes/origin/work-btls:
>>>git for-each-ref --format='%(refname:short) <- %(upstream:short)' refs/heads
SomeLocalBranchName <- remotes/origin/work-btls
master <- origin/master
>>>git status
On branch SomeLocalBranchName
Your branch is up-to-date with 'remotes/origin/work-btls'.

Categories

Resources