Adding a basic unit test

Twisted comes with it's own unit testing framework that is aware of the twisted
ecosystem.

The initial test contains a basic setUp, tearDown and one test case.

The setUp method is run before each test and is used to initialize state needed
by unit tests themselves. Our setup code contains a reactor running our jsonrpc
service over HTTP.

The reactor is the core component of the twisted event loop driving our application.
We didn't have to use the reactor previously since the internet.TCPServer handled it
for us under the covers. Twisted comes with many specialized reactors for different use
cases, the default one uses epoll on Linux but one can also use a GTK+ or wx reactors
for desktop application usage or the kqueue reactor on FreeBSD. For now it's enough
to know that the reactor allows us to run our service in isolation from the rest
of the application.

Second part of the setUp method initializes a jsonrpc client connected over HTTP with
our service. txjsonrpc.web.jsonrpc.Proxy will handle all the marshaling between JSON
and python types so we won't have to work directly with JSON in our test code.
The version parameter allows us to specify the protocol version used by the client.

The tearDown method is much simpler and consists only of stopping the listener on our reactor.
Generally tearDown is responsible for cleaning up all the state initialized in setUp, it's being
run after each test finishes.

The actual test code is contained in test_jsonrpc_snapshots_empty. Methods with their name
starting with test_ are automatically detected as test cases and run accordingly by trial.

The test code itself is far more interesting as it exposes additional architecture of the twisted
framework itself - the Deferred.

A Deferred in twisted is a mechanism for data transmission between asynchronous code. A potentially blocking function (due to waiting on data from the network as an example) immediately returns a Deferred to which a caller can attach callbacks and errbacks (an errback is a function called on when an error occurs). The Deferred will automatically run the first callback or errback (if there was an error) the moment at which the function results become available. In summary a Deferred is a promise that at some point in the future the function will have a result or an error.

The callRemote from our method returns a Deferred immediately the moment it's called - even though
the communication between the client and the service didn't yet happen. Performing the actual communication is driven by the twisted framework - our options for now are limited to adding callbacks and errbacks to the returned Deferred object. In our case, we add a local callback _result function which will be called the moment our service call results are available. In the function itself we perform tests checking that the error code is null, the result is present and that the result is an empty list.

Having all the parts together. We can start running tests using the trial application distributed along with twisted. Trial is a tool used for unit test execution it handles both tests written using the twisted unit test framework and the standard python test framework. The benefit of trial is the ability to automatically detect tests in the application and the ability to control their execution
and output format.

To run the tests issue:
 $ trial shutter