Archive

Archive for the ‘Windows Service Bus’ Category

Transient faults and testing

October 31, 2014 1 comment

In this post I am going to talk about the transient fault exception handling block and how we can unit test using mock. So we start by getting the Transient Fault Handling Application from Nuget.

PM> Install-Package EnterpriseLibrary.TransientFaultHandling

Although in the package description it mentions about windows azure but it can be used for any .Net component. In fact if you are doing any serious .net enterprise development I highly recommend using this in your application. And as it happens to be that I am working on a On-Premise Windows Service Bus and I had to build a robust capability of handling transient faults so I used it for my service bus code as well as for SQL Server, SQL Azure, Blob Storage, SFTP etc.

The one simple rule for using this application block is that you have define an error detection strategy (a class) which implements the ITransientErrorDetectionStrategy interface and then wire it with retry policy class of the application block and that’s it you are up and running.

So the code I am going to write is a simple OrderService which picks up Orders which are in the state of "Not Processed" and takes the Id’s of the orders and send the message to the bus. For brevity I have left all the details and specific and just wrote this demo like code. The main focus of this post is on writing effective unit tests for fail/retry logic.

Lets start cutting some code with our Order POCO class, some interface to mock EntityFramework context and a OrderService which will coordinate the whole task.

OrderStatus.cs

public enum OrderStatus
{
    NotProcessed,
    InTransition,
    Shipped
}

IOrderContext.cs

public interface IOrderContext
{
    DbSet<Order> Order { get; set; }
}

Order.cs

public class Order
{
    public int Id { get; set; }

    // omitted for brevity
    public OrderStatus Status { get; set; }
}

IServiceBus.cs

public interface IServiceBus
{
    void Send(BrokeredMessage messages, string queueName);
}


Now we will define our error detection strategy as following.

MessagingCommunicationErrorDetectionStrategy.cs

public class MessagingCommunicationErrorDetectionStrategy 
                : ITransientErrorDetectionStrategy
{
    public bool IsTransient(Exception ex)
    {
        var commException = 
                    ex as MessagingCommunicationException;

        if (commException != null)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

And this is order service which will fetch some unprocessed orders using EntityFramework and send them to the service bus.

OrderService .cs

public class OrderService : IOrderService
{
    private readonly IServiceBus serviceBus;

    private readonly IOrderContext orderContext;

    public OrderService(IServiceBus serviceBus, IOrderContext orderContext)
    {
        this.serviceBus = serviceBus;
        this.orderContext = orderContext;
    }

    public void Process()
    {
        var orders = orderContext
                        .Order
                        .Where(x => x.Status == OrderStatus.NotProcessed)
                        .ToList();

        var retryPolicy = 
            new RetryPolicy<MessagingCommunicationErrorDetectionStrategy>(5);

        orders.ForEach(o => 
                retryPolicy.ExecuteAction(() => 
                                            this.serviceBus.Send
                                            (
                                                new BrokeredMessage
                                                    {
                                                        MessageId = o.Id.ToString()
                                                    },
                                                    "orderqueue")
                                            ));
    }
}

As you can see for quick demo purpose I have hard coded the creation of the retry policy but in a real production application I would refactor that into an interface and inject it using Dependency Injection.

Now lets write some unit tests to cover following scenarios.

  • Happy case where everything runs smoothly and no exceptions happens.
  • Exception is thrown from our test but retry logic takes care of it.
  • Exception is thrown and all the retry attempts are exhausted.

I am going to use Moq to mock and in-memory list of orders and wire that up to EntityFrameWork DbSet so that when the service asks the OrderContext to get order records, it retrieves it from the in-memory list rather than going to a physical database. In the happy case scenario I will fetch 5 records from the in-memory database and process them and verify that the service bus Send() method is called exactly the same number of times as we have records in the DbSet. However in the second test I will just fetch only one record to verify that the service bus send method is called twice as the first call did failed due to the exception.

WhenUsingOrderService.cs

  [TestClass]
  public class WhenUsingOrderService
  {
      private Mock<IServiceBus> serviceBusMock;

      private Mock<IOrderContext> contextMock;

      private Mock<DbSet<Order>> dbSetMock;

      private OrderService orderService;

      [TestInitialize]
      public void Setup()
      {
          contextMock = new Mock<IOrderContext>();
          dbSetMock = new Mock<DbSet<Order>>();
          serviceBusMock = new Mock<IServiceBus>();
      }

      [TestMethod]
      public void ShouldBeAbleToSendMessage()
      {
          this.BuildDbSetMock(5);
          orderService = new OrderService(serviceBusMock.Object,
                                          contextMock.Object);

          orderService.Process();

          serviceBusMock.Verify(
                              x => x.Send(It.IsAny<BrokeredMessage>(),
                              "orderqueue"),
                              Times.Exactly(dbSetMock.Object.Count()));
      }

      [TestMethod]
      public void ShouldBeAbleToHandleMessagingCommunicationException()
      {
          bool firstTimeExecuteCalled = true;

          serviceBusMock
              .Setup(
                      x => x.Send(It.IsAny<BrokeredMessage>(),
                      "orderqueue"))
              .Callback(() =>
              {
                  if (firstTimeExecuteCalled)
                  {
                      firstTimeExecuteCalled = false;
                      throw new
                          MessagingCommunicationException("CommunicationException");
                  }
              });
          this.BuildDbSetMock(1);
          orderService = new OrderService(serviceBusMock.Object,
                                          contextMock.Object);

          orderService.Process();

          serviceBusMock.Verify(
                              x => x.Send(It.IsAny<BrokeredMessage>(),
                                          "orderqueue"),
                                          Times.Exactly(2));
      }

      [TestMethod]
      public void ShouldBeAbleToReachMaximumRetries()
      {
          int callCount = 1;
          serviceBusMock
                  .Setup(
                          x => x.Send(It.IsAny<BrokeredMessage>(),
                          "orderqueue"))
                  .Callback(() =>
                  {
                      if (callCount < 5)
                      {
                          callCount++;
                          throw new MessagingCommunicationException("CommunicationException");
                      }
                  });
          this.BuildDbSetMock(1);
          orderService = new OrderService(serviceBusMock.Object,
                                          contextMock.Object);
          try
          {
              orderService.Process();
          }
          catch (Exception ex)
          {
              Trace.WriteLine(ex.Message);
          }

          Trace.WriteLine(string.Format("Reached the maximun reties count of {0}", callCount));
          
          serviceBusMock.Verify(
                              x => x.Send(It.IsAny<BrokeredMessage>(),
                                          "orderqueue"),
                                          Times.Exactly(5));
      }

      private void BuildDbSetMock(int numberOfOrders)
      {
          var orders = OrderDataProvider.GetOrders()
                                        .Take(numberOfOrders)
                                        .AsQueryable();

          dbSetMock.As<IQueryable<Order>>()
                   .Setup(m => m.Provider)
                   .Returns(orders.Provider);

          dbSetMock.As<IQueryable<Order>>()
                   .Setup(m => m.Expression)
                   .Returns(orders.Expression);

          dbSetMock.As<IQueryable<Order>>()
                   .Setup(m => m.ElementType)
                   .Returns(orders.ElementType);

          dbSetMock.As<IQueryable<Order>>()
                   .Setup(m => m.GetEnumerator())
                   .Returns(orders.GetEnumerator());

          contextMock.Setup(x => x.Order)
                     .Returns(dbSetMock.Object);
      }
  }

As you can see, it’s a pretty slick test to cover up all the scenarios and I am using the Callback() method in our mock setup to create failure scenarios and throw exception. The complete source code is available at my skydrive.

Advertisement

Windows Service Bus Setup Guide

September 30, 2014 Leave a comment

In this post I am going to show you step by step installation of Windows Service Bus on a Windows 8.Windows Service Bus is the On-Premise version of Azure Service Bus and it is a nice way for companies to start using the on premise service bus specially in Australia where the Azure Data Center is still not available.I think it will also benefits businesses to see the potential of the service bus in terms of integration and they can start planning their systems for the cloud.This will make their system migration more manageable and less risky.

The good thing from a developer point of view is that with this setup guide you can do a quick proof of concept without having full-blown Windows Server 2012 and SQL Server and start showing its capability for building up an Enterprise Service Bus.

So lets first start with installing SQL 2012 Express and you can download a copy from here. Just run the installer and select all the features to be installed as shown below.

SQL Server all features

For all of my development work I prefer to have mixed mode authentication for SQL Server and in the wizard select the mixed mode authentication and continue with rest of the installation steps.If everything goes smoothly you will see the SQL Server installation is complete.

SQL Server successfully installed

Before we can start installing the windows service bus make sure you have Web Platform Installer (WPI) on your machine and I know if you are doing any .NET development you probably have it.Search for Service Bus from WPI search and you will see the following results.

search for service bus

Select the first and third option i.e. "Windows Azure Pack:Service Bus 1.1" and the update associated with this pack and follow the installation as shown below.

search for service bus

search for service bus

search for service bus

search for service bus

Now through your Windows Search look for "Service Bus" and you should be able to see two results as shown below.

Select Create a New Farm and continue.

search for service bus

It will show you the SQL Server instance running on your machine and click to test whether the connection to the database server is working or not.

Along with the "Service Bus Configuration" you also get "Service Bus Powershell" so lets open up the Service Bus Powershell and type in the following command.

PS C:\Program Files\Service Bus\1.1> Get-SBClientConfiguration

This will give you the connection string to your service bus and you are good to go. So now you have a service bus environment up and running on your developer machine.

Please follow my Azure Service Bus post to see how we can send and receive messages from the service bus and how to use the "Service Bus Explorer".

That is all for today folks.