After deploying a website don't assume it succeeded - add automated tests to check everything works.

Back in the old days you would open a browser and check your new version of the site works - make sure IIS is running, the app pools starts, your database login credentials are valid etc. A human sanity check is always good - i still do it often - but ideally I want to know during deployment if something simple like that has caused the deploy to break the system. Automation is your friend here - smoke tests to the rescue.

I use an Octopus Deploy step template to make a http request to key pages on my site - the home page, the status page etc. That way if the basics have broken my octopus release is failed before I even need to check it manually.

Octopus has a great library of open source custom step templates (source on github), and the one I use for endpoint smoke testing is Http Test. Sometimes the site is behind authentication and I need to login before it is considered "not on fire" and the deploy can succeed, and recently this caused me a problem - in the form of Kerberos.

I needed check a site that used Windows Authentication had deployed ok and the HTTP Test step only supported basic or anonymous authorisation so I decided to role up my sleeves and give back to the octopus community. Under the hood step templates are just Powershell, and under that you have access to most of .net so passing a kerberos auth token was not that hard - I just used System.Net.WebRequest with the appropriate System.Management.Automation.PSCredential.

Using Octopus variables means the username and password can be securely stored inside Octopus or prompted for at the start of the deploy. They even obfuscate the password in the logs for you.

The new feature is just an opt in checkbox, check it out:

I also made a pull request into the public octopus deploy library on github to add this new feature there too and it was accepted within a few hours. The guys over at octopus really do a good job of dev friendly tooling.

Finally Powershell gurus can review the script below if you are interested, or even fork it and make it better.

$uri = $OctopusParameters['Uri']
$expectedCode = [int] $OctopusParameters['ExpectedCode']
$timeoutSeconds = [int] $OctopusParameters['TimeoutSeconds']
$Username = $OctopusParameters['AuthUsername']
$Password = $OctopusParameters['AuthPassword']
$UseWindowsAuth = $OctopusParameters['UseWindowsAuth']

Write-Host "Starting verification request to $uri"  
Write-Host "Expecting response code $expectedCode."

$timer = [System.Diagnostics.Stopwatch]::StartNew()
$success = $false
do  
{
    try
    {
        if ($Username -and $Password -and $UseWindowsAuth)
                     {
                         Write-Host "Making request to $uri using windows authentication for user $Username"
                         $request = [system.Net.WebRequest]::Create($uri)
                         $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $(ConvertTo-SecureString -String $Password -AsPlainText -Force)
                $request.Credentials = $Credential 

                try
                {
                    $response = $request.GetResponse()
                }
                catch [System.Net.WebException]
                {
                    Write-Host "Request failed :-( System.Net.WebException"
                    Write-Host $_.Exception
                    $response = $_.Exception.Response
                }

                     }
              elseif ($Username -and $Password)
                     {
                         Write-Host "Making request to $uri using basic authentication for user $Username"
                           $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $(ConvertTo-SecureString -String $Password -AsPlainText -Force)
                           $response = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing -Credential $Credential
                     }
              else
                     {
                         Write-Host "Making request to $uri using anonymous authentication"
                           $response = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing
                     }

        $code = $response.StatusCode
        Write-Host "Recieved response code: $code"

        if($response.StatusCode -eq $expectedCode)
        {
            $success = $true
        }
    }
    catch
    {
        # Anything other than a 200 will throw an exception so
        # we check the exception message which may contain the 
        # actual status code to verify

        Write-Host "Request failed :-("
        Write-Host $_.Exception

        if($_.Exception -like "*($expectedCode)*")
        {
            $success = $true
        }
    }

    if(!$success)
    {
        Write-Host "Trying again in 5 seconds..."
        Start-Sleep -s 5
    }
}
while(!$success -and $timer.Elapsed -le (New-TimeSpan -Seconds $timeoutSeconds))

$timer.Stop()

# Verify result

if(!$success)  
{
    throw "Verification failed - giving up."
}

Write-Host "Sucesss! Found status code $expectedCode"