binary dreams

a world of 1s and 0s

How to check the results of an XPath query against an XML document using the SmokeTester

In June 2014 my ex-colleague open sourced a smoke test tool that we began using at our previous

In June 2014 my ex-colleague open sourced a smoke test tool that we began using at our previous company. It was originally created by another colleague to be used for deployment testing. You could check a WCF service responds as expected, a database connection succeeds or the AppSettings in a configuration file are as expected.

I had a problem recently where I needed to confirm my WiX installer had successfully set the website Windows Authentication providers to "NTLM, Negotiate" - in that order. To do this I needed to create a brand new smoke test - the XMLDocumentTest.

The idea of this smoke test is to run an XPath query over an XML document. In my test I needed to check the IIS applicationHost.config file. Here is a sample of it's contents:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<location path="Fake Application">
<system.webServer>
<security>
<authentication>
<digestAuthentication enabled="false" />
<basicAuthentication enabled="false" />
<windowsAuthentication enabled="true">
<providers>
<clear />
<clear />
<add value="NTLM" />
<add value="Negotiate" />
</providers>
</windowsAuthentication>
</authentication>
</security>
</system.webServer>
</location>
</configuration>

Then if you run this XPath query over it.

/configuration/location[@path='Fake Application']/system.webServer/
security/authentication/windowsAuthentication/providers/add

You should get this result.

<add value="NTLM" />
<add value="Negotiate" />

I highly recommend the XPathBuilder application to work out your query for the smoke test.

The smoke test will look like this. Make sure the XPathQuery and ExpectedOutput elements have no line breaks, otherwise the test will not succeed.

<?xml version="1.0" encoding="utf-16"?>
<ConfigurationTestSuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>XMLDocumentTests</Name>
<Description>This a sample smoke test of the XMLDocumentTest</Description>
<Tests>
<Test xsi:type="XMLDocumentTest">
<TestName>Check Windows Auth providers</TestName>
<Path>C:\location\of\configfile\</Path>
<Filename>applicationHost.config</Filename>
<XPathQuery>/configuration/location[@path='Fake Application']/system.webServer/
security/authentication/windowsAuthentication/providers/add</XPathQuery>
<ExpectedOutput><add value="NTLM" /><add value="Negotiate" /></ExpectedOutput>
</Test>
</Tests>
</ConfigurationTestSuite>

To use the tool you can run this command. Make sure the InstallationSmokeTest.exe and smoke test file are together when running it.

InstallationSmokeTest.exe Run FakeSmokeTest.xml

At the time of posting the new test is only in the Main branch. You can download the latest Smoke Tester from CodePlex and read more information on the smoke tester here.

How to enable your Wix installer to upgrade your application

To  help reduce the amount of manual steps required in my change management form I needed to avoid uninstalling and installing our product.

To do this I found a way in WiX to upgrade the product using the following.

<Upgrade Id="PUT_UPGRADECODE_GUID_HERE">
<UpgradeVersion OnlyDetect="yes" 
Minimum="!(bind.FileVersion.YOUR_PROJECT_DLL.dll)" 
Property="NEWERVERSIONDETECTED" 
IncludeMinimum="no" />
<UpgradeVersion OnlyDetect="no" 
Maximum="!(bind.FileVersion.YOUR_PROJECT_DLL.dll)" 
Property="OLDERVERSIONBEINGUPGRADED" 
IncludeMaximum="no" />
<!-- Detect for changes in 4th field only -->
<UpgradeVersion Property="ANOTHERBUILDINSTALLED" 
Maximum="!(bind.FileVersion.YOUR_PROJECT_DLL.dll)" 
Minimum="!(bind.FileVersion.YOUR_PROJECT_DLL.dll)" 
IncludeMinimum="yes" 
IncludeMaximum="yes" 
OnlyDetect="no" />
</Upgrade>

In your Product.wxs file. Change the ProductId attribute to just an asterisk(*). The UpgradeCode attribute should stay as it is.

<Product Id="*" Name="Your Project" 
Language="1057" 
Version="!(bind.FileVersion.YOUR_PROJECT_DLL.dll)" 
Manufacturer="Your Company Ltd" 
UpgradeCode="PUT_UPGRADECODE_GUID_HERE">

Now add the complete <Upgrade> section. Put it near the top between the <Media> and the <UI> tags.

The <Upgrade> Id in should be the same GUID as the UpgradeCode in the <Product> tag above.

Change the YOUR_PROJECT_DLL to your DLL.  

To stop an install of an older version over a newer version add the following tag before the <InstallExecuteSequence>. 

<CustomAction Id="CA_BlockOlderVersionInstall" 
Error="A later version of [ProductName] is already installed. Setup will now exit." />
<InstallExecuteSequence> ...

Add the following to the start of your <InstallExecuteSequence> tag.

<InstallExecuteSequence>
<Custom Action="CA_BlockOlderVersionInstall" After="FindRelatedProducts">
<![CDATA[NEWERVERSIONDETECTED]]>
</Custom>
<LaunchConditions After="AppSearch" />
<!-- Schedule RemoveExistingProducts early -->
<RemoveExistingProducts After="InstallInitialize" />
... other custom actions ...
</InstallExecuteSequence>

Now test it!