Monday, September 26, 2011

Setting up CCNet in combination with VS2010

In this post I'll describe how one can set up CCNet to work with VS2010. Not everyone has the full blown version of TFS at their disposal.

Scenario setup

I always use the following setup at work :
  • Project_CI : for Continuous Integration (compile, unit-test)
  • Project_MakePackage : this makes the install package (compile, unit-test,integration-test, make package)
  • Project_QA : this does unit-test, integration_test, coverage and code analysis.
This is a pragmatic approach: a 'fix' can be deployed even when for example coverage is still below X percent, as long as all tests are passed. It's convention that QA must be fixed ASAP!

The CI must be as fast as possible, so it runs only the unit-tests. The CI project has an interval trigger checking the repo every 5 minutes. This project does NOT label TFS.

The makePackage project has a schedule trigger : every day at 20:00, and a labeler so we can easily branch via a label.

The QA project also has a schedule trigger : every day at 21:00. This project does NOT label TFS.

Step 1 : Setting up the source control part


In Tfs itself I have the following layout :

ProjectName
\__Main
| \Lib
| \Src
\__Releases
\__1_0_0_3450
| \Lib
| \Src
\__1_0_1_5678
\Lib
\Src
This allows for easy branching.

Step 2 : Setting up CCNet.config

I use the pre-processor to reduce a lot of the configuration. This allows me to define a CCNet project in just 30 lines!
You can read the full configuration for the tfs source control at the wiki Tfs Source Control
My advise : set the deleteworkspace and cleancopy to true, this prevents a lot of problems.
A full example of ccnet.config with comparable layout is at the bottom of this post.
The preprocessor declaration :
<cb:define name="vsts_ci">
<server>http://tfs-server:8080/tfs/default/</server>
<username>cruise</username>
<password>**********</password>
<domain>tfs-server</domain>
<autoGetSource>true</autoGetSource>
<cleanCopy>true</cleanCopy>
<force>true</force>
<deleteWorkspace>true</deleteWorkspace>
</cb:define>

The source control block inside a project :
<sourcecontrol type="vsts">
<workspace>$(ProjectName)</workspace>
<project>$/$(ProjectName)/Main</project>
<cb:vsts_ci/>
</sourcecontrol>

Step 3 : Setting up the build script


The main action lays of course in the build script, for which I use Nant. The reason I (still) use Nant is that I know it rather well, and it works. For compiling I just call the MSBuild task from NantContrib pointing to the VS2010 solution, but all other logic is in Nant.
An example of the Nant build script is also at the bottom of this post.

Step 4 : Testing with Ms-test


Like I said in the beginning, I have 2 kind of tests, UnitTests and Integration Tests. In MS-test I create a test-list with the name UnitTests directly under the root item. All tests in this list, and in test-lists beneath it will be ran when I specify UnitTests. The 'Integration Tests' (slow running ones, going to the database, ...) are in a test-list named IntegrationTests also directly under the root item. Here's an example of calling MS-Test via nant :
<exec program="${mstest_exe}">
<arg value="/testmetadata:${mstest_metadatafile}" />
<arg value="/resultsfile:MStest_Results.xml" />
<arg value="/testlist:UnitTests" />
<arg value="/testlist:IntegrationTests" if="${CCNetBuildCondition=='ForceBuild'}" />
</exec>


Step 5 : Using Ms-Test with coverage


In Ms-test you can specify that you also want coverage to run, see for setting it up.
I just made a company rule that for code coverage to be ran via ccnet, the testsettings file must be named : CodeCoverage.testsettings,
with a specific base name(cover_me) and no timestamps appended. Just to make things easier for me.
If you want MS-Test to run coverage, just pass the testsettings as an extra argument :
<exec program="${mstest_exe}" failonerror="false" resultproperty="testresult.temp" >
<arg value="/testmetadata:${mstest_metadatafile}" />
<arg value="/resultsfile:MStest_Results.xml" />
<arg value="/testsettings:CodeCoverage.testsettings" />
<arg value="/testlist:UnitTests" />
<arg value="/testlist:IntegrationTests" if="${CCNetBuildCondition=='ForceBuild'}" />
</exec>


There is a catch : Ms-Test from VS2010 does not produce XML anymore, see this post for a solution. You really need the dll from VS2008 for it to work, the VS2010 has another interface sadly enough. So best to digg up you DVD of VS2008. I've updated that program a bit so that is also removes the Lines from the coverage result file, making it a lot smaller to merge. Below is my source code (its VB.Net)

Showing the results


I've added 2 new xsl files (MsTestReport2010.xsl and MsTest2010Cover.xsl) to CCNet, you can use these in the dashboard in the build plugins.
<buildPlugins>
...
<xslReportBuildPlugin description="Ms Test" actionName="MSTest" xslFileName="xsl\MsTestReport2010.xsl" />
<xslReportBuildPlugin description="MS Test Coverage" actionName="MSTest2008Cover" xslFileName="xsl\MsTestCover2010.xsl"/>
...
</buildPlugins>





Attachments


CCNet.config

<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- preprocessor settings -->
<cb:define WorkingDir="D:\WorkingFolders\" />
<cb:define WorkingMainDir="D:\ArtifactFolders\" />
<cb:define ArtifactsDir="\Artifacts" />

<cb:define name="vsts_ci">
<server>http://tfs-server:8080/tfs/default/</server>
<username>cruise</username>
<password>**********</password>
<domain>tfs-server</domain>
<autoGetSource>true</autoGetSource>
<cleanCopy>true</cleanCopy>
<force>true</force>
<deleteWorkspace>true</deleteWorkspace>
</cb:define>

<cb:define name="vsts_package">
<server>http://tfs-server:8080/tfs/default/</server>
<username>cruise</username>
<password>**********</password>
<domain>tfs-server</domain>
<autoGetSource>true</autoGetSource>
<cleanCopy>true</cleanCopy>
<force>true</force>
<applyLabel>true</applyLabel>
<deleteWorkspace>true</deleteWorkspace>
</cb:define>

<cb:define name="common_publishers">
<merge>
<files>
<file>Coverage.xml</file>
<file>MStest_Results.xml</file>
<file>simian.xml</file>
</files>
</merge>
<xmllogger />
<statistics />
<modificationHistory onlyLogWhenChangesFound="true" />
<artifactcleanup cleanUpMethod="KeepLastXSubDirs" cleanUpValue="2" />
<artifactcleanup cleanUpMethod="KeepLastXBuilds" cleanUpValue="25000" />
<email from="CruiseControl@TheBuilder.com"
mailhost="TheMailer.Company.com"
includeDetails="TRUE">
<groups/>
<users/>
<converters>
<ldapConverter domainName="Company" />
</converters>
<modifierNotificationTypes>
<NotificationType>Failed</NotificationType>
<NotificationType>Fixed</NotificationType>
</modifierNotificationTypes>
</email>
</cb:define>

<cb:define name="nant_common">
<executable>c:\Tools\nant\bin\nant.exe</executable>
<nologo>true</nologo>
<buildTimeoutSeconds>1800</buildTimeoutSeconds>
<buildArgs>-D:useExtraMsbuildLogger=true -D:isCI=true -listener:CCNetListener,CCNetListener -D:configuration=Debug</buildArgs>
</cb:define>

<cb:define name="nant_package">
<executable>c:\Tools\nant\bin\nant.exe</executable>
<nologo>true</nologo>
<buildTimeoutSeconds>1800</buildTimeoutSeconds>
<buildArgs> -D:useExtraMsbuildLogger=true -D:CreateInstallZips=true -listener:CCNetListener,CCNetListener -D:configuration=Release</buildArgs>
</cb:define>

<cb:define name="nant_qa">
<executable>c:\Tools\nant\bin\nant.exe</executable>
<nologo>true</nologo>
<buildTimeoutSeconds>3600</buildTimeoutSeconds>
<buildArgs>-D:useExtraMsbuildLogger=true -listener:CCNetListener,CCNetListener -D:configuration=DebugCA</buildArgs>
</cb:define>

<cb:define name="nant_target_CI">
<targetList>
<target>clean</target>
<target>compile</target>
<target>test</target>
</targetList>
</cb:define>

<cb:define name="nant_target_qa">
<targetList>
<target>clean</target>
<target>simian</target>
<target>compile</target>
<target>cover</target>
</targetList>
</cb:define>

<cb:define name="nant_target_package">
<targetList>
<target>clean</target>
<target>compile</target>
<target>test</target>
<target>make_package</target>
<target>makehelp</target>
</targetList>
</cb:define>
<!-- end preprocessor settings -->


<!-- Projects -->
<cb:scope ProjectName="ProjectX">
<cb:define ProjectType="_CI" />
<project name="$(ProjectName)$(ProjectType)" queue="Q1" queuePriority="901">
<workingDirectory>$(WorkingDir)$(ProjectName)$(ProjectType)</workingDirectory>
<artifactDirectory>$(WorkingMainDir)$(ProjectName)$(ProjectType)$(ArtifactsDir)</artifactDirectory>

<labeller type="defaultlabeller" />

<sourcecontrol type="vsts">
<workspace>$(ProjectName)</workspace>
<project>$/$(ProjectName)/Main</project>
<cb:vsts_ci/>
</sourcecontrol>

<tasks>
<nant>
<cb:nant_common/>
<cb:nant_target_CI />
</nant>
</tasks>

<publishers>
<cb:common_publishers />
</publishers>

</project>
</cb:scope>

<cb:scope ProjectName="ProjectX">
<cb:define ProjectType="_Package" />
<project name="$(ProjectName)$(ProjectType)" queue="Q1" queuePriority="801">
<workingDirectory>$(WorkingDir)$(ProjectName)$(ProjectType)</workingDirectory>
<artifactDirectory>$(WorkingMainDir)$(ProjectName)$(ProjectType)$(ArtifactsDir)</artifactDirectory>

<labeller type="defaultlabeller">
<prefix>1.0.1.</prefix>
<incrementOnFailure>false</incrementOnFailure>
</labeller>

<sourcecontrol type="vsts">
<workspace>$(ProjectName)</workspace>
<project>$/$(ProjectName)/Main</project>
<cb:vsts_package/>
</sourcecontrol>

<tasks>
<nant>
<cb:nant_package/>
<cb:nant_target_package />
</nant>
</tasks>

<publishers>
<cb:common_publishers />
</publishers>

</project>
</cb:scope>

<cb:scope ProjectName="ProjectX">
<cb:define ProjectType="_QA" />
<project name="$(ProjectName)$(ProjectType)" queue="Q1" queuePriority="801">
<workingDirectory>$(WorkingDir)$(ProjectName)$(ProjectType)</workingDirectory>
<artifactDirectory>$(WorkingMainDir)$(ProjectName)$(ProjectType)$(ArtifactsDir)</artifactDirectory>

<labeller type="defaultlabeller" />

<sourcecontrol type="vsts">
<workspace>$(ProjectName)</workspace>
<project>$/$(ProjectName)/Main</project>
<cb:vsts_package/>
</sourcecontrol>

<tasks>
<nant>
<cb:nant_common/>
<cb:nant_target_qa />
</nant>
</tasks>

<publishers>
<cb:common_publishers />
</publishers>

</project>
</cb:scope>

</cruisecontrol>


Nant Build Script

<project default="help">
<property name="solution" unless="${property::exists('solution')}" value="ProjectX.sln" />
<property name="configuration" unless="${property::exists('configuration')}" value="Debug" />
<property name="CCNetListenerFile" unless="${property::exists('CCNetListenerFile')}" value="listen.xml" />
<property name="msbuildverbose" unless="${property::exists('msbuildverbose')}" value="normal" />
<property name="CCNetLabel" unless="${property::exists('CCNetLabel')}" value="0.0.0.0" />

<property name="mstest_metadatafile" value="ProjectX.vsmdi" />

<property overwrite="false" name="Simian_exe" value="c:\Tools\simian\bin\simian-2.3.32.exe" />
<property overwrite="false" name="msbuildlogger" value="C:\Program Files\CruiseControl.NET\server\MSBuildListener.dll" />
<property overwrite="false" name="versionInfofile" value="VersionInfo.cs" />
<property overwrite="false" name="mstest_exe" value="C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\mstest.exe" />

<!-- custom scripts -->
<script language="C#" prefix="RuWi">
<references>
<include name="System.Xml.dll" />
<include name="System.dll" />
</references>
<imports>
<import namespace="System.Text" />
</imports>
<code>
<![CDATA[
[Function("UpdateVersionFile")]
public static bool UpdateVersionFile(string inputFile, string newVersion, bool debugMode)
{
bool ok = true;
try
{
System.IO.StreamReader versionFile = new System.IO.StreamReader(inputFile, System.Text.Encoding.ASCII);
string line = "";
System.Text.StringBuilder result = new StringBuilder();
string searchPatternVersion = @"(\d+\.\d+\.\d+\.\d+)";
string searchPatternAssemblyProduct = string.Format(@"AssemblyProduct\({0}(.*?)\{0}", "\"");
string replacePatternAssemblyProduct = string.Format(@"AssemblyProduct({0}(Debug)${1}1{2}{0}", "\"", "{", "}");

while (!versionFile.EndOfStream)
{
line = versionFile.ReadLine();

if (System.Text.RegularExpressions.Regex.IsMatch(line, searchPatternVersion) && (line.Contains("AssemblyFileVersion")))
{
line = System.Text.RegularExpressions.Regex.Replace(line, searchPatternVersion, newVersion);
}

if (debugMode && System.Text.RegularExpressions.Regex.IsMatch(line, searchPatternAssemblyProduct))
{
line = System.Text.RegularExpressions.Regex.Replace(line, searchPatternAssemblyProduct, replacePatternAssemblyProduct);
}

result.AppendLine(line);
}

versionFile.Close();

System.IO.StreamWriter updatedVersionfile = new System.IO.StreamWriter(inputFile);
updatedVersionfile.Write(result.ToString());
updatedVersionfile.Close();
}
catch (Exception ex)
{
ok = false;
Console.WriteLine(ex.ToString());
}
return ok;
}
]]>
</code>
</script>

<target name="help" >
<echo message="Removed for keeping the file shorter." />
</target>

<target name="clean" description="deletes all created files">
<delete >
<fileset>
<patternset >
<include name="**/bin/**" />
<include name="**/obj/**" />
<include name="Coverage*.xml" />
<include name="*.zip" />
<include name="MStest_Results.xml" />
<include name="simian.xml" />
</patternset>
</fileset>
</delete>
</target>

<target name="adjustversion" description="Adjusts the version in the version.info file">
<if test="${not file::exists(versionInfofile)}">
<fail message="file: ${versionInfofile} which must contains the version info was NOT found" />
</if>

<echo message="Setting version to ${CCNetLabel}" />

<property name="debugMode" value = "False" />
<property name="debugMode" value = "True" if="${configuration=='Debug'}" />
<if test="${not RuWi::UpdateVersionFile(versionInfofile,CCNetLabel,debugMode)}">
<fail message="updating file: ${versionInfofile} which must contains the version info failed" />
</if>
</target>

<target name="compile" description="compiles the solution in the wanted configuration" depends="adjustversion">
<msbuild project="${solution}" >
<arg value="/p:Configuration=${configuration}" />
<arg value="/p:CCNetListenerFile=${CCNetListenerFile}" />
<arg value="/v:${msbuildverbose}" />
<arg value="/l:${msbuildlogger}" />
</msbuild>
</target>

<target name="test" description="runs the tests" depends="deploy.services">
<if test="${string::get-length(mstest_metadatafile)>0}" >
<exec program="${mstest_exe}">
<arg value="/testmetadata:${mstest_metadatafile}" />
<arg value="/resultsfile:MStest_Results.xml" />
<arg value="/testlist:UnitTests" />
<arg value="/testlist:IntegrationTests" if="${CCNetBuildCondition=='ForceBuild'}" />
</exec>
</if>
</target>

<target name = "cover" description="runs the tests with coverage" >
<if test="${string::get-length(mstest_metadatafile)>0}" >
<!--
company rule : code coverage settings must be set via this file
with the following NamingScheme : baseName="cover_me" appendTimeStamp="false" useDefault="false"
-->
<if test="${file::exists('CodeCoverage.testsettings')}">

<exec program="${mstest_exe}" failonerror="false" resultproperty="testresult.temp" >
<arg value="/testmetadata:${mstest_metadatafile}" />
<arg value="/resultsfile:MStest_Results.xml" />
<arg value="/testsettings:CodeCoverage.testsettings" />
<arg value="/testlist:UnitTests" />
<arg value="/testlist:IntegrationTests" if="${CCNetBuildCondition=='ForceBuild'}" />
</exec>

<property name="TestsOK" value="false" unless="${int::parse(testresult.temp)==0}"/>

<property name="DataCoverageFilePath" value="${RuWi::FindFile('cover_me','data.coverage')}" />
<property name="TurnCoverageFileIntoXml_exe" value="C:\Tools\TurnCoverageFileIntoXml\TurnCoverageFileIntoXml.exe" />

<fail message="No data.coverage found in cover_me folder" unless="${string::get-length(DataCoverageFilePath)>0}" />

<echo message="DataCoverageFilePath : ${DataCoverageFilePath}" />

<exec program="${TurnCoverageFileIntoXml_exe}" >
<arg value="${DataCoverageFilePath}" />
<arg value="cover_me\Out" />
<arg value="NCoverExplorer.xml" />
</exec>

<fail message="Failures reported in unit tests." unless="${TestsOK}" />
</if>
</if>

</target>

<target name="simian" description="find duplicate code" >
<exec program="${Simian_exe}" failonerror="false">
<arg value="-includes=**/*.cs" />
<arg value="-excludes=**/*Designer.*" />
<arg value="-excludes=**/*Generated.*" />
<arg value="-excludes=**/*Reference.*" />
<arg value="-excludes=**/obj/*" />
<arg value="-threshold=10" />
<arg value="-formatter=xml:simian.xml" />
</exec>
</target>

<target name="deploy.services" description="deploys all service (web/wcf)" /> <!-- company specific, just copies files to the iis folder -->
<target name="make_package" description="makes install packages" /> <!-- company specific, creates install packages and zips them -->
<target name="makehelp" description="makes install packages" /> <!-- company specific, makes user help with custom tool -->

</project>


Source code for Ms-Test binary2Xml

Imports Microsoft.VisualStudio.CodeCoverage

Module Module1

Sub Main()
Dim Arguments As String()
Dim obc = Console.BackgroundColor
Dim returnValue As Integer = 0

Try
Arguments = Environment.GetCommandLineArgs

If Arguments.Length <> 4 Then

Console.BackgroundColor = ConsoleColor.Blue
Console.WriteLine("Usage : {0} DataCoverageFilePath CoveredFilesPath ResultXmlFilePath", Arguments(0))
Console.BackgroundColor = ConsoleColor.DarkGreen
Console.WriteLine(" {0} In\LTREMRUBEN\data.coverage Out d:\codecover.xml", Arguments(0))
Console.BackgroundColor = obc
returnValue = 1
Exit Try
End If

Dim DataCoverageFilePath As String = Arguments(1)
Dim CoveredFilesPath As String = Arguments(2)
Dim ResultXmlFilePath As String = Arguments(3)

CoverageInfoManager.ExePath = CoveredFilesPath
CoverageInfoManager.SymPath = CoveredFilesPath

Console.WriteLine("converting {0}", DataCoverageFilePath)
Dim coverage = CoverageInfoManager.CreateInfoFromFile(DataCoverageFilePath)

Dim CoverResult = coverage.BuildDataSet(Nothing)

Dim CoverResultStream As New IO.MemoryStream
CoverResult.WriteXml(CoverResultStream)

Console.WriteLine("Initial Size in bytes : {0}", CoverResultStream.Length)
CoverResultStream.Position = 0


Console.WriteLine("Cleaning up xml info ...")
Dim CoverResultXmlDoc As New Xml.XmlDocument()
CoverResultXmlDoc.Load(CoverResultStream)

Dim LineInfos = CoverResultXmlDoc.SelectNodes("//Lines")

For Each lineInfo As Xml.XmlNode In LineInfos
lineInfo.RemoveAll()
Next

Dim SourceFileNameInfos = CoverResultXmlDoc.SelectNodes("//SourceFileNames")
For Each SourceFileNameInfo As Xml.XmlNode In SourceFileNameInfos
SourceFileNameInfo.RemoveAll()
Next

CoverResultXmlDoc.PreserveWhitespace = False
CoverResultXmlDoc.Normalize()
CoverResultXmlDoc.Save(ResultXmlFilePath)

Console.WriteLine("Compressed Size in bytes : {0}", New IO.FileInfo(ResultXmlFilePath).Length)

Console.WriteLine("Done.")

Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub

End Module

Saturday, September 10, 2011

Statistics publisher

There was an issue that the statistics publisher does not work correctly. Now I know the statistics publisher is an old one, and one where the configuration is rarely altered, besides the 10 standard foreseen statistics.
Gathering extra statistics is not that difficult, add a name for the element, and a XPath expression. For example:
<statistic name="AmountOfFailures" xpath="sum(//test-results/@failures)" />
Now this is good when the build log is simple xml, but when you have sections with namespaces, things become nasty.
If you're working with VS2010, and are merging the test results, you have encountered this problem before. These test results are stored in the "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" namespace.
This problem is now fixed, I've added support for namespaces.

Below you'll find a xmlFile containing test data coming from a demo project, and I'll use this file as an example :
Suppose you want to know the total amount of tests and the amount of failed ones. This information can be retrieved via the following XPath queries : /TestRun/ResultSummary/Counters/@total and /TestRun/ResultSummary/Counters/@failed
Because the test-result file is merged into the master buildlog file, the TestRun node is not the root node anymore.
Normally you could/would fix this by changing it into //TestRun/ResultSummary/Counters/@total, giving the following config for the statistic :
<statistic name="AmountOfTests" xpath="//TestRun/ResultSummary/Counters/@total" />
But this gives MS.Internal.Xml.XPath.XPathSelectionIterator as result. Not very intuitive if you do not work with XPath every day.The problem is the // operator, XPath asumes there can be many TestResult nodes in the xmlfile(even if we know there will only be one), and returns an iterator. To bypass this kind of thing, a FirstMatch class was (and still is) foreseen to handle this, resulting in following setting :
<firstMatch name="AmountOfTests" xpath="//TestRun/ResultSummary/Counters/@total" />
But now the result is Null (empty string) in the file. With the support for namespaces, the config is as follows :
<firstMatch name="AmountOfTests" xpath="//mstest:TestRun/mstest:ResultSummary/mstest:Counters/@total" >
<namespaces>
<namespaceMapping prefix="mstest" url="http://microsoft.com/schemas/VisualStudio/TeamTest/2010" />
</namespaces>
</firstMatch>

Resulting in the wanted result of 2 for the file below. This is a huge step forward, but there is still a problem :
suppose you want some statistic with a calculation of a setting with a namespace, and one without a namespace.
This poses a problem with XSLT 1.0, because we can not set a prefix for the default namespace. To overcome that problem we'll have to support XSLT 2.0. where there is functionality foreseen.
This request is added on the todo list.
The test file :


<TestRun id="32083ab3-68fe-40ab-a13d-c289aef12a28"
name="cover_me"
runUser="ruben"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestSettings name="Cover"
id="9839cf84-0738-4c12-885d-99158bdda72f">
<Description>These are default test settings for a local test run.</Description>
<Deployment userDeploymentRoot="C:\Users\ruben\Documents\Visual Studio 2010\Projects\CCNetStatistics"
useDefaultDeploymentRoot="false"
runDeploymentRoot="cover_me" />
<NamingScheme baseName="cover_me"
appendTimeStamp="false"
useDefault="false" />
<Execution>
<TestTypeSpecific>
<UnitTestRunConfig testTypeId="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b">
<AssemblyResolution>
<TestDirectory useLoadContext="true" />
</AssemblyResolution>
</UnitTestRunConfig>
</TestTypeSpecific>
<AgentRule name="LocalMachineDefaultRole">
<DataCollectors>
<DataCollector uri="datacollector://microsoft/CodeCoverage/1.0"
assemblyQualifiedName="Microsoft.VisualStudio.TestTools.CodeCoverage.CoveragePlugIn, Microsoft.VisualStudio.QualityTools.Plugins.CodeCoverage, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
friendlyName="Code Coverage">
<Configuration>
<CodeCoverage xmlns="">
<Regular>
<CodeCoverageItem binaryFile="C:\Users\ruben\Documents\Visual Studio 2010\Projects\CCNetStatistics\CCNetStatistics\bin\Debug\Agents.dll"
pdbFile="C:\Users\ruben\Documents\Visual Studio 2010\Projects\CCNetStatistics\CCNetStatistics\bin\Debug\Agents.instr.pdb"
instrumentInPlace="true" />
</Regular>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</AgentRule>
</Execution>
</TestSettings>
<Times creation="2011-09-04T20:40:22.8989434+02:00"
queuing="2011-09-04T20:40:24.1937456+02:00"
start="2011-09-04T20:40:24.3341459+02:00"
finish="2011-09-04T20:40:28.0469524+02:00" />
<ResultSummary outcome="Failed">
<Counters total="2"
executed="2"
passed="1"
error="0"
failed="1"
timeout="0"
aborted="0"
inconclusive="0"
passedButRunAborted="0"
notRunnable="0"
notExecuted="0"
disconnected="0"
warning="0"
completed="0"
inProgress="0"
pending="0" />
<ResultFiles>
<ResultFile path="LTREMRUBEN\data.coverage" />
</ResultFiles>
</ResultSummary>
<TestDefinitions>
<UnitTest name="TestInfiltration"
storage="c:\users\ruben\documents\visual studio 2010\projects\ccnetstatistics\testagents\bin\debug\testagents.dll"
id="93fe6bec-7340-59e7-ba45-0a396dc614ff">
<Execution id="792491ae-0c70-45e3-a474-1f1cb130226b" />
<TestMethod codeBase="c:/users/ruben/documents/visual studio 2010/projects/ccnetstatistics/testagents/bin/debug/TestAgents.DLL"
adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
className="TestAgents.UnitTest1, TestAgents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="TestInfiltration" />
</UnitTest>
<UnitTest name="TestReport"
storage="c:\users\ruben\documents\visual studio 2010\projects\ccnetstatistics\testagents\bin\debug\testagents.dll"
id="09504e3d-ea5f-fda7-5ee0-32f8cc895784">
<Execution id="c98799b7-8675-43b9-ae03-7eb7fd2acb70" />
<TestMethod codeBase="c:/users/ruben/documents/visual studio 2010/projects/ccnetstatistics/testagents/bin/debug/TestAgents.DLL"
adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
className="TestAgents.UnitTest1, TestAgents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="TestReport" />
</UnitTest>
</TestDefinitions>
<TestLists>
<TestList name="Smoke"
id="39ed6b71-dbd6-41f1-a30d-eebe96ec74ff"
parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<TestLinks>
<TestLink id="93fe6bec-7340-59e7-ba45-0a396dc614ff"
name="TestInfiltration"
storage="c:\users\ruben\documents\visual studio 2010\projects\ccnetstatistics\testagents\bin\debug\testagents.dll"
type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="09504e3d-ea5f-fda7-5ee0-32f8cc895784"
name="TestReport"
storage="c:\users\ruben\documents\visual studio 2010\projects\ccnetstatistics\testagents\bin\debug\testagents.dll"
type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Lists of Results"
id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6" />
<TestList name="All Loaded Results"
id="19431567-8539-422a-85d7-44ee4e166bda" />
</TestLists>
<TestEntries>
<TestEntry testId="93fe6bec-7340-59e7-ba45-0a396dc614ff"
executionId="792491ae-0c70-45e3-a474-1f1cb130226b"
testListId="39ed6b71-dbd6-41f1-a30d-eebe96ec74ff" />
<TestEntry testId="09504e3d-ea5f-fda7-5ee0-32f8cc895784"
executionId="c98799b7-8675-43b9-ae03-7eb7fd2acb70"
testListId="39ed6b71-dbd6-41f1-a30d-eebe96ec74ff" />
</TestEntries>
<Results>
<UnitTestResult executionId="792491ae-0c70-45e3-a474-1f1cb130226b"
testId="93fe6bec-7340-59e7-ba45-0a396dc614ff"
testName="TestInfiltration"
computerName="LTREMRUBEN"
duration="00:00:00.0342893"
startTime="2011-09-04T20:40:25.9721488+02:00"
endTime="2011-09-04T20:40:26.3777495+02:00"
testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"
outcome="Passed"
testListId="39ed6b71-dbd6-41f1-a30d-eebe96ec74ff"
relativeResultsDirectory="792491ae-0c70-45e3-a474-1f1cb130226b">
</UnitTestResult>
<UnitTestResult executionId="c98799b7-8675-43b9-ae03-7eb7fd2acb70"
testId="09504e3d-ea5f-fda7-5ee0-32f8cc895784"
testName="TestReport"
computerName="LTREMRUBEN"
duration="00:00:00.0538581"
startTime="2011-09-04T20:40:26.4089495+02:00"
endTime="2011-09-04T20:40:26.4713496+02:00"
testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"
outcome="Failed"
testListId="39ed6b71-dbd6-41f1-a30d-eebe96ec74ff"
relativeResultsDirectory="c98799b7-8675-43b9-ae03-7eb7fd2acb70">
<Output>
<ErrorInfo>
<Message>Assert.AreEqual failed. Expected:&lt;&gt;. Actual:&lt;all went ok&gt;. </Message>
<StackTrace>
at TestAgents.UnitTest1.TestReport() in c:\users\ruben\documents\visual studio 2010\Projects\CCNetStatistics\TestAgents\UnitTest1.vb:line 17
</StackTrace>
</ErrorInfo>
</Output>
</UnitTestResult>
</Results>
</TestRun>