Pester, Jenkins, Remote & ExitCode

 

Continuous integration needs your systems and deployments to be totally controlled and tested. Pester is a good framework for that. I’ve already write about it on this blog.

For one of our customer Iโ€™ve worked hand to hand with them on Infrastructure Continuous Delivery in Windows Environment.

I won’t speak about the VMWare, Chef & Jenkins Integration here, Iโ€™ll make another blogpost about it later, but let me share with you what i learned about Pester integration with Jenkins.

 

As we have deployed our solution and built our server, we are now in the Jenkins Post Build task. In order to be able to execute a script after a build, you’ll need to install this plugin: https://wiki.jenkins-ci.org/display/JENKINS/PostBuildScript+Plugin

You use it, go the the Post-Build Actions section, choose Post build task in the Add post-build action drop down box.

Post build task

The Log text filed is here in order to trigger script regarding what is happening in the log, you can add multiple conditions to build complicated scenarios.

[su_label type=”info”]All the console output will be stored in memory in order to parse it, if you want to avoid that, just close the Log text Windows. [/su_label]

Now to get a correct exit code we need to use a switch called –EnableExit available within the Invoke-Pester cmdlet. The problem is that if we want to use Pester remotely to test our targetย  we have few options:

  1. Install Jenkins Slave on target in order to execute script locally -> Maybe the best choice, but my customer didn’t want that solution because it needed new rules on firewall…
  2. Use Invoke-Command -computerName <target> -scriptblock { invoke-command } -> can’t get back the exit code ๐Ÿ™‚
  3. Use the remotely plugin -> the solution we choose.

Another thing is that we want our Pester script to receive arguments from the Jenkins, so at first you’ll need a script to launch the Pester tests.

The script can be something like that to test few stuff regarding an IIS site ๐Ÿ˜‰

[CmdletBinding()]
param (
    [Parameter(Mandatory=$true)]
    [String]$Source,
    [String]$IISRoot,
    [String]$OutFile,
    [String]$IISSite,
    [String]$IISPool,
    [String]$Target
 )

 Try {

     Write-verbose "Executing Pester tests"
       
        # Create a machineconfig.csv file
        $ConfigFile = "C:\Program Files\WindowsPowerShell\Modules\remotely\machineConfig.csv"
        Remove-item $ConfigFile -force
        echo "ComputerName,Username,Password" > $ConfigFile
        echo $target >> $ConfigFile
    
        # Go to the Pester tests directory
 	cd "$source\Pester"

        # Execute tests
 	    Invoke-Pester -verbose -OutputFile "$Source\$OutFile"  -OutputFormat NUnitXml `
                      -EnableExit -Script @{ Path = "$Source\Pester"; Parameters = @{
                                                             IISSite = $IISSite;
                                                             IISPool = $IISPool;};}
 
 }
 Catch {
    Exit 1
 }

 

Let me explain Invoke-Pester parameters. I need XML outputted file in NUnit XML format in order to put results in Job’s front page. The -script allows me to pass a hash table to Pester with various parameters.

This script has to be on the root of your application folder in your source control management tool. Regarding the Pester tests, you’ll have to put file in a directory called Pester that’ll be committed and available in your Jenkins workplace after. The Pester script will look like this

param (
    [String]$IISSite,
    [String]$IISPool
)

Describe "ValidateWebSite" {

    # Check if IIS is installed
    It "IIS Service Started" {
        $Result = Remotely { Get-Service W3SVC } 
	$Result.Status | Should be "Running"
    }

    # Check if Website is created
    It "IIS Web Site started" {
        $Result = Remotely { param($IISSite) Get-Website -Name $IISSite } -ArgumentList $IISSite
	$Result.State | Should be "Started"
    }
    
    # Check if Application exsists
    It "IIS Application Pool Started" {
        $Result = Remotely { param($IISPool) Get-WebAppPoolState -name $IISPool }  -ArgumentList $IISPool
	$Result.Value | Should be "Started"
    }
}

 

In order to get remotely module to work, you’ll need WinRM flows opened on your network between Jenkins and the target, and in addition to record target in machineConfig.csv file located at the root of the remotely plugin. To be clear it’s not fully, but the cheat on the script that is running Pester tests is totally good working. Just be sure that the Jenkins service account is in the target’s administrator group and it’ll work.

In the Post build task script use the following command (remove the carriage return) to get the script launched as well as the exit code in order to change the build status if a check is failing.

powershell.exe -executionpolicy bypass 
               -command "& %WORKSPACE%\WebSite\RunPester.ps1 
               -Source %WORKSPACE%\WebSite
               -Target website01.dev.local
               -IISRoot D:\Inetpub\Application 
               -Outfile test.XML 
               -IISSite Application 
               -IISPool ApplicationPool -verbose; exit $lastexitcode"

 

[su_label type=”important”]Do not use the -File parameter of powershell.exe because it won’t return the exit code (in Jenkins)[/su_label]

 

To finish, add a Post-Build Action called Publish NUnit test result report, and in the XML path, put ../*.XML in order to get all NUnit tests to be printed in root page job.

You now have a totally working remotely Pester tests with results imported in Jenkins. KENAVO !