PLEASE NOTE: This is for Visual Studio 2010. For the VS2012 version, please click here.
This series of posts will show you how to provision VmWare machines, install Test Controllers and Test Agents, register those with TFS and construct a Physical Environment within Lab Center so that it can be targeted by Microsoft Test Manager. All automatically using PowerShell (and VmRun.EXE):
Build-Deploy-Test with VmWare is a superset of this so I will tackle that after this series.
See Part 2 for Requirements (PowerShell, Vix etc.).
Do not use this code under any circumstances (should just about cover the possibilities!).
I am using an undocumented API in order to construct the Physical Environment in Lab Center and set up the Test Controller Topology. I have tested the registered environments using MTM, use it often and come to no grief. My Lab Center and TFS system appears to be stable. But you use this at your own risk! At the very least, it would be sensible to do a full back up of your TFS Installation and ideally test this prior to production deployment. In particular:
this has not yet been tested with Visual Studio 2010 Server Pack 1 (it has now, and it appears to work as well as pre-SP1) but use at your own risk
In future, if and when Microsoft provides a way to create Phyical environments and construct Test Controller / Test Agent hierarchies programmatically, this is the only stage you will have to change in this series. Everything else you have done as part of this series still applies.
That aside: this is the REALLY AWESOME PART!! Before going on, consider provisioning a brand new virtual machine using the scripts at the end of Part 4.
There are no officially supported APIs to manage the Test Controllers and Test Agents in TFS. This is unfortunate because it stops you creating Physical Environments and constructing your Test Controller / Test Agent hierarchies on the fly. You proceed at your own risk!
The Test Controllers and Test Agents are all written in .Net and Microsoft has a tendency to make all of its classes ‘internal’ so you cannot reuse them willy-nilly. I like this approach: rather than obfuscating their code they are polite enough to let us wander around their work if we need to in order to troubleshoot or find out WTF is going on. It’s a pragmatic solution between opening things up to all and sundry and having to support their firstborn for life.
The code we need to invoke to construct our Test Controller and Test Agent hierarchies is stored in ‘internal’ classes so we need to find a way of instantiating those classes and invoking their methods.
A major help is that IL has no concept of ‘internal’: it is the compiler that enforces that contract (well… its not THAT simple!) opening up all kinds of creative possibilities! But that aside, you can create internal classes from other libraries just by using reflection like so:
System.Reflection.Assembly controllerAssembly = System.Reflection.Assembly.LoadFile(theAssemblyPath); Type controllerTestEnvironmentType = controllerAssembly.GetType(theFullyQualifiedTypeName); object testEnvironment = controllerTestEnvironmentType.InvokeMember("", System.Reflection.BindingFlags.CreateInstance, null, controllerTestEnvironmentType, null);
The reason I am mentioning it? Because you will see it in my code when I invoke the internal or private Test Controller classes:
dynamic controllerConnectionManagerWrapper = new AccessPrivateWrapper(controllerConnectionManager); controllerConnectionManagerWrapper.UpdateTestEnvironment(testEnvironment);
Manually creating a Physical Environment using a UI
The source code this time includes all of the scripts and some supporting Visual Studio 2010 Solutions that you will have to build yourself:
The first thing we need to do is to make sure you can manually construct Physical Environments using my User Interface because it drives the underlying TFS libraries. If not: not much point going on!
Assuming you have heeded the disclaimer, you will need to add references to several standard TFS API’s including:
The interesting three are:
It is important you set *ALL* of those DLL’s to ‘Copy local: True’ for the Reference. You will need to add them to AgentInteraction and PhysicalEnvironments as well.
Now run the PhysicalEnvironments application and you will see a glorious ‘Graham UI’. I loathe arty-farty work and I loathe writing User Interfaces so much, and have consistently done such a bad job of it, that I never get asked to write them any more (mission accomplished!). Select the TFS Team Project Collection / Team Project and observe what happens:
This UI is listing all of the Test Controllers on the left: that is the same list you see when you create a new environment in Lab Center and are asked to select the Test Controller you want to create the environment on:
When you select one of the Test Controllers (such as Moo1250) you will see the list of Agents available. This list is identical to what you can see in Lab Center as well:
So we have all of the information we need to start constructing Physical Environments. Enter a new name for the Physical Environment you want to create – such as “WooHOO” – tick the single Agent, enter a sensible Role name, and select “Create New Environment”:
Your UI will now gloriously lock up for about a minute (I provide no UI Cues) whilst Lab Center does whatever it needs to do to create your environment. Assuming all went well (you’ll know when focus returns to your window) you should be able to see your environment in Lab Center:
AWESOME! So we have all the bits and pieces.
Before going on, delete the environment in Lab Center and then continue.
Automating the creation of a Physical Environment using PowerShell
The PowerShell script obviously doesn’t use the User Interface but I have created a dirty, hackey-wackey Console application called ‘AgentInteraction.EXE’ that is only moderately unforgiving of command line mistakes but can be used to drive the registration process.
To set this up to work, create a new subdirectory under VisualStudioGumpf called AgentInteraction and drop these DLL’s (AgentHelpers/bin/Debug), AgentInteraction.EXE and anything pulled in as part of the build into it:
Assuming you have removed the Test Controller and everything from Lab Center, you should be able to execute code like this:
# Obtain a list of all Agents known to a Test Controller \\10.0.0.1\VisualStudioGumpf\AgentInteraction\AgentInteraction.EXE Command=ListAgents TestControllerUri="MOO1251.WOOHOO.COM:6901" # To create an environment on the Test Controller MOO1251 and with a single Agent called MOO1251 with a Role of 'Desktop Client' you would execute: \\10.0.0.1\VisualStudioGumpf\AgentInteraction\AgentInteraction.EXE command=RegisterEnvironment testcontrolleruri="MOO1251.WOOHOO.COM:6901" TeamProjectName="TestSample" EnvironmentName="My New Environment" Agents="MOO1251,The Web Server"
… and see your environment created in Lab Center from PowerShell:
Assuming everything is in place, you should now be able to dynamically provision new virtual machines in VmWare, install the Test Controllers and Test Agents, register them with TFS and create a new Physical Environment on a whim. The key differences for this post are:
# ... variables from previous stages # The Team Project Name we want to register the environment with and the environment name $TeamProjectName = "TestSample"; $EnvironmentName = "My Brand New Environment"; $MachineRole = "Database Server"; # ... # STAGE 5: Create the Environment # It can take a while for the VM to spin up and the Test Controller + Test Agent to come online... so use the RETRYCOUNT here. Invoke-Expression "$VisualStudioGumpfUnc\AgentInteraction\AgentInteraction.EXE command=RegisterEnvironment testcontrolleruri=$($MachineName).$($DomainName):6901 TeamProjectName=`"$TeamProjectName`" EnvironmentName=`"$EnvironmentName`" Agents=`"$MachineName,$MachineRole`" RetryCount=10"; Agents=`"$MachineName,$MachineRole`" ";
As a final test, set it as a targettable environment in MTM and run your Tests:
Mission Accomplished! However… there is an anomoly! When I went into the Test Controllers view and clicked a Test Controller, I noticed that duplicate Test Controller names appeared for those that were put on Virtual Machines that I had provisioned:
At first I thought it was some SID issue with the cloned virtual machine but it appears to be down to a legacy DNS Issue:
I was able to repeat this 100%. If you remove the legacy DNS Record (ie: for Moo1400 which is a virtual machine I purged) and restart MTM, the problem goes away (I wasn’t able to repeat it after this).
So I guess you need to purge the DNS Record as well as the Computer from your Active Directory when you throw away an environment.