:: Introduction
When developing on the Microsoft Windows Azure Platform, a storage and compute emulator is available for running applications via the Windows Azure Tools (as of writing this post I am using v1.6). An Azure application package can be deployed to the emulator (running locally) instead of to an actual Azure compute node in the Azure cloud. The benefits of this are two-fold:
- Deployments to the emulator are dramatically faster (it takes seconds to deploy to the emulator as opposed to minutes to deploy to the Azure cloud)
- There are no additional costs associated with deploying to and/or using the emulator to run an application package since the emulator is a locally installed application (deploying to the Azure cloud would incur additional compute and bandwidth charges).
Therefore when I needed to create some automated tests to run against various WCF web methods that were apart of my Azure web role, I first needed to deploy my web role (within the Azure package) to the Azure emulator. Note that I wanted to be able to run the automated tests both locally and on our development team's continuous (CI) server, therefore the solution I chose needed to accomodate both environments.
:: Force the Azure Project to Package during Compilation
Before an Azure package can be deployed to the emulator it must first be packaged. Since v1.4 of the Windows Azure Tools, the csx folder and its contents are no longer generated during compilation (See these release notes for v1.4 and search for the breaking change: "PackageForComputeEmulator"). So in order to force the generation of the csx folder we need to specify that the package should be generated for the compute emulator within the Azure project file (*.ccproj). I embedded the this within an existing property group containing some other items:
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<CloudExtensionsDir Condition=" '$(CloudExtensionsDir)' == '' ">$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\1.6\</CloudExtensionsDir>
<!-- This flag generates the 'csx' package folder when this project is compiled (it does not require a separate package command) -->
<PackageForComputeEmulator>true</PackageForComputeEmulator>
</PropertyGroup>
:: Deploying to the Azure Compute Emulator
Now that we have the csx package folder generated after each compilation run we can use the CSRun command-line tool to deploy the folder to the emulator at the start of each test suite run. I was able to accomplish this as cleanly as possible by embedding the package deployment within our testing framework's assembly initialize method which looks like the following:
public static void Initialize(TestContext context)
{
var emulator = ConfigurationSettings.Settings["AzureEmulator"];
var computeArgs = ConfigurationSettings.Settings["AzureComputeArguments"];
using (var process = new Process())
{
process.StartInfo = new ProcessStartInfo(emulator, computeArgs);
process.Start();
process.WaitForExit();
Assert.AreEqual<int>(0, process.ExitCode, "Starting the Azure compute emulator and loading it with a package failed");
}
}
And the 2 configuration settings I used above look like the following:
<appSettings>
<add key="AzureEmulator" value="C:\Program Files\Windows Azure Emulator\emulator\csrun.exe" />
<add key="AzureComputeArguments" value="..\..\..\..\source\Project.Azure\csx\Release ..\..\..\..\source\Project.Azure\bin\Release\ServiceConfiguration.cscfg" />
</appSettings>
:: Cleaning-up the Azure Compute Emulator
Once the test suite run is complete, clean-up should take place in which the previously deployed package is removed from the compute emulator and the compute emulator is shutdown. Both of these tasks require a slight work around due to the lack of options available for the CSRun command-line tool.
A single deployed package can be removed from the compute emulator if its deployment identifier is available (see the "/remove:<DeploymentId>" option on this page). However keeping track of the deployment identifier would require some additional logic that is not needed. This logic could be built but instead I elected to simply remove ALL deployed packages using the "/removeAll" option. I did this because I only deploy one package at a time (future implementations could be more sophisticated and allow for multiple deployments but at the moment I have elected for the simplest approach).
Removing all the deployment packages (as mentioned above) does just that, it does not shutdown the Azure compute emulator. Unfortunately the CSRun command-line tool does not provide a shutdown option for the compute emulator (like ti does for the storage emulator) so I have elected to kill the process manually after the test run.
The following code in the testing framework's assembly cleanup method does what I have described above:
public static void Cleanup()
{
var emulator = ConfigurationSettings.Settings["AzureEmulator"];
using (var process = new Process())
{
process.StartInfo = new ProcessStartInfo(emulator, "/removeAll");
process.Start();
process.WaitForExit();
Assert.AreEqual<int>(0, process.ExitCode, "Removing all the packages from the Azure compute emulator failed");
}
foreach (var process in Process.GetProcessesByName("DFService"))
{
process.Kill();
process.WaitForExit();
}
}
:: Conclusion
Once the configuration and code changes mentioned above have been included in the Azure project and the testing framework the Azure package will be deployed into the Azure compute emulator at the beginning of each and every test suite run. Subsequently at the end of the test suite run the Azure package will be "un-deployed"and the Azure compute emulator will be forcibly shutdown. Note that this works both locally for developers running automated tests as well as on our development team's continuous integration (CI) server that is using NAnt and MSBuild to compile and test the application.