Thursday, 30 October 2014

Using Process Monitor to solve a file copy failure during an automated build

The Problem

We use CruiseControl.Net (CCNet) for continuous integration and also for automated deployment of applications. The deployment processes usually include compiling an application, configuring it appropriately for a target environment (e.g. test, production, etc.), creating a deployment package such as a Zip archive, and then copying the package to the appropriate server(s) where it is installed.

However, we suddenly started getting failures when running these deployment builds. After checking the CCNet build logs we could see errors such as “Could not find a part of the path \\servername\deploymentfolder”.

Initial checks on the build server showed that the Universal Naming Convention (UNC) paths were actually valid. So what was going on?

The Solution

To find out what was going on I used Process Monitor to see if there were issues accessing the UNC paths.

Firstly, I grabbed the latest version of Process Monitor from Microsoft SysInternals. It’s free and does not need installation – it runs as a single executable. Then I copied Process Monitor (procmon.exe) to the machine in question and ran it. Once it has opened I did the following:

  1. Disabled event capture by clicking the magnifying glass icon so it has the red ‘X’ overlay.
  2. Clicked the eraser icon to clear all existing captured events.
  3. Made sure Process Monitor was only going to capture file system activity by only selecting the filing cabinet icon.

procmon

Then I needed to add a filter so I only saw events relating to the file/folder I was interested in:

  1. Clicked the filter icon (the Filter > Filter… menu option does the same thing).
  2. Once the Process Monitor Filter dialog opened, clicked the Reset button.
  3. Using the drop-down menus etc. created a filter that said “Path begins with \\servername\deploymentfolder then include”.
  4. Clicked the Add button to add the new filter.

procmon2

Finally I clicked the magnifying glass icon again to start event capture and forced one of the failing builds to run. Once the build completed I stopped capturing events again. This was the result:

SNAGHTML2522739c

So I could see that NAnt had been unable to copy the deployment file to the server because of a login failure. By double-clicking on an entry in the event list I could see more details about the issue including which account was being used.

Further digging identified the cause of the issue being related to the account being used to run the CCNet service and was easy to correct.

Thursday, 23 October 2014

Date operations with Noda Time

I was looking at a coding exercise recently that consisted of source code that needed refactoring. Embedded in part of the code was a check to see if someone was 21 or over. I thought this was a great chance to use the Noda Time library created by Jon Skeet to create nicely understandable code. Noda Time is described in the following terms:

“Noda Time is an alternative date and time API for .NET. It helps you to think about your data more clearly, and express operations on that data more precisely.” [1]

So, here’s a quick piece of playful code using Noda Time to check a person’s age in years. Firstly, let’s create a service interface.

using System;

namespace AgeService
{
    public interface IAgeService
    {
        bool IsOfAgeAtDate(DateTime dateOfTest, DateTime dateOfBirth, int expectedAgeInYears);
    }
}

Now let’s implement the interface.

using System;
using NodaTime;

namespace AgeService
{
    public class AgeService : IAgeService
    {
        public bool IsOfAgeAtDate(DateTime dateOfTest, DateTime dateOfBirth, int expectedAgeInYears)
        {
            var localDateOfTest = new LocalDate(dateOfTest.Year, dateOfTest.Month, dateOfTest.Day);
            var localDateOfBirth = new LocalDate(dateOfBirth.Year, dateOfBirth.Month, dateOfBirth.Day);

            Period age = Period.Between(localDateOfBirth, localDateOfTest, PeriodUnits.Years);

            return age.Years >= expectedAgeInYears;
        }
    }
}

A LocalDate is the date portion of a Noda Time LocalDateTime that has no concept of the time of day; it's just a date. A Period described as follows:

“A Period is a number of years, months, weeks, days, hours and so on, which can be added to (or subtracted from) a LocalDateTime, LocalDate or LocalTime. The amount of elapsed time represented by a Period isn't fixed: a period of "one month" is effectively longer when added to January 1st than when added to February 1st, because February is always shorter than January.” [2]

Finally here are a couple of simple tests to demonstrate it works.

using System;
using NUnit.Framework;

namespace AgeServiceTests
{
    [TestFixture]
    public class AgeServiceTests
    {
        [Test]
        public void IsOfAgeAtDate_WhenOfCorrectAge_ReturnsTrue()
        {
            // Arrange
            var ageService = new AgeService.AgeService();
            var dateOfTest = new DateTime(2014, 10, 23);
            var dateOfBirth = new DateTime(1993, 10, 23);

            // Act
            var result = ageService.IsOfAgeAtDate(dateOfTest, dateOfBirth, 21);

            // Assert
            Assert.That(result, Is.True);
        }

        [Test]
        public void IsOfAgeAtDate_WhenUnderAge_ReturnsFalse()
        {
            // Arrange
            var ageService = new AgeService.AgeService();
            var dateOfTest = new DateTime(2014, 10, 23);
            var dateOfBirth = new DateTime(1993, 10, 24);

            // Act
            var result = ageService.IsOfAgeAtDate(dateOfTest, dateOfBirth, 21);

            // Assert
            Assert.That(result, Is.False);
        }
    }
}

There’s lots more to Noda Time than that but it’s a start! Happy coding.

References

[1] http://nodatime.org

[2] http://nodatime.org/1.3.x/userguide/core-types.html

Thursday, 23 October 2014