How we built Rover

logo

Rover is Enterprise Tester’s new companion. Rover is a portable client for ET that lets you run your tests anywhere, even when you don’t have an internet connection to your ET server. We’ve just released version 1 of Rover, and this version is a Windows application. That means you can run it on your windows laptop or tablet. However, we’ve always intended for Rover to be an iPad and Android application as well, to let you test anywhere, on any device. In this article, I’m going to talk about some of the technologies that are helping to make this vision a reality.


Rover’s Goals

When we sat down and planned what we wanted from a portable ET client, we came up with the following goals:

  1. It would allow you to run your tests, no matter where you are.
  2. It would be easy and fun to use.
  3. Your test results would be synced back to ET and look like any other test run, so results can be viewed and reported on.
  4. Control over what is synchronized and when, saving on bandwidth and time.

These goals gave us the following requirements:

  • Storage of ET data off-line in a local database, so you can still execute and raise defects when there’s no internet connection to ET.
  • Run on multiple platforms.
  • Native applications on each platform, to provide a superior user experience.
  • New User Experience which is simpler, more stream lined and touch-friendly.
  • Use of existing test script, script assignment, script run and incident entities – so you can make use of all the test scripts, reports and TQL queries you already have.
  • Ability to control what data is synchronized to Rover from ET, and what changed entities are synchronized back to ET.

Let’s go over some of the technologies that enabled these requirements to be met:

Cross platform development

In order to avoid rewriting absolutely everything for each platform that we wanted to target, we investigated different cross-platform development languages and tools. Our first consideration was to build Rover with html, since ET is already built in html, and there are systems like Apache Cordova that let you take an html application and package it as a platform executable, with added features that browsers don’t usually get access to such as reading files and taking photos. However, we decided that we wanted to build Rover using native controls, because that would let us build the smoothest, most familiar application we could.

We quickly agreed that Xamarin was the best choice for us. Xamarin is a platform that lets you write all your code in C#, and then run that C# code on any Windows, Linux, Android or iOS device. We liked that it didn’t try to provide a write once, run anywhere framework: with Xamarin you still have to build the front end of each platform every time, because you’re directly calling into native APIs: in Windows we use WPF (Windows Presentation Foundation) for the UI and on iOS we will use Cocoa Touch for the UI.

We also used a framework called MvvmCross to help build Rover. MvvmCross is designed to work with Xamarin, helping you to organise your code in such a way that you get maximum reusability out of the parts of code that can be shared between platforms.

In the end, across all the code we wrote for Rover, 62% will be reusable when we build an iOS or Android version. The remaining 38% of the code is all WPF (the Windows UI framework) specific.

LOC

API Access

ET has a very comprehensive REST API. We knew that Rover would be able to communicate to ET through the existing API, and we wouldn’t have to add any new endpoints to it. However, we had been used to calling the API from JavaScript, which is a very unstructured, dynamic language. Rover is written in C#, and therefore benefits from a strong typing system. If we were building a SOAP API we’d be able to generate proxy classes from a WSDL, but with REST, there are less options for formally specifying the data shapes and endpoints of your API. This is probably because such things are far less necessary with REST, but we still wanted to strongly-type our C# REST client code.

We considered WADL but decided that Swagger was the best option. We rolled out Swagger support in ET version 4.8. This enabled many of our customers to get a much better handle on what our API enables, especially with the Swagger UI. Check out Alex’s post for more details about Swagger in ET. But what Alex doesn’t tell you is that what drove us to add Swagger in the first place was Rover. We used the Swagger output to generate a really easy-to-use C# wrapper for ET’s API. We’ve also open sourced that for our customers to use.

Offline storage

We knew Rover would need to persist data on the local device – offline storage is its reason for being. We needed something that wouldn’t require complex installation, and would behave the same on every platform we deployed it to. This was a no-brainer: SQLite is a relational database that is already supported on all the platforms we are targeting. In addition, SQLite has a really easy-to-use wrapper for .NET / Xamarin, and a ready-to-use plugin for MVVMCross.

Our usage of SQLite was a little non-traditional, though. Instead of treating it as a RDBMS where every property of every entity was pulled out into a column (which would have been very hard, as many of our entities are both complex and customisable), we treated it a lot like a key-value store. Each entity was stored in a table that had columns for the IDs, any properties we might want to query by (such as text fields and relationship ids like ProjectID), and a big text column that stored the entity JSON, just as we got it from the API. Updating an entity in our data access layer would automatically update these key columns, making it very easy to query.

Sync Workflow

We always knew that synchronising data between Rover and ET was going to be one of the hardest problems when building Rover. We decided to avoid potential merge conflicts by reducing the types of changes that Rover can make: In V1, Rover can’t edit an existing Incident, only comment on it or create a brand new one. Also, Rover can only create new Test Runs, it won’t let you edit a Test Run that already exists on the server. These restrictions simplify merges, but tracking the state of any item is still a complex piece of logic.

We decided to build a mini-workflow engine into Rover for the Sync state of any entity. This engine can take any state (such as “Not Downloaded”) and any input (such as “Download”) and know what actions need to occur to shift the entity into the correct next state (in this case, we need to insert the local entity from the data from the server, and that will take us to the “Synced” state).

To make this easier to understand, we built a mini-DSL into Rover that allowed us to describe these states, inputs and outputs. This DSL is an extension of a language called “DOT” from IBM that also allows us to generate a human-readable diagram from the same source file. Here is that diagram (click to zoom in):

State Diagram

As you can see, the number of states and transitions is not trivial! We were really glad we didn’t have to hand-code each of these, because whenever we wanted to revise our state diagram (for example, the state “DeletedOnServer” was added very near the end of the development) we could just regenerate our workflow code from the simple DSL.

Try Rover!

I hope that’s been an interesting insight into some of the technologies we used to bring you Rover. If you haven’t tried it yet, you can find out more or request a free trial from our website. We hope you like it!

Comments are closed.