Cynic – Test Harness to Make Your System Under Test Cynical

by Ruslan Spivak on June 3, 2012

These days almost any application has several integration points like database, payment gateway, or some Web service that it consumes over HTTP.

All communication with the remote systems happens over the network and both networks and those systems often go wonky.

If we do not test the behavior of our system when the remote end operates out of spec and goes haywire the only place for testing becomes in production which is, as we all know, for some systems is less than acceptable.

Because the calls to the remote systems use network, the socket connection can have different failure scenarios, for example:

  • The remote end resets the connection by sending a TCP RST packet
  • The connection may be established, but the response is never sent back and the connection is not closed (If you don’t use socket timeouts in your app you may be in trouble at some point).
  • The remote end can send garbage data as the response
  • The service can send HTML over HTTP instead of the expected JSON response
  • The HTTP service can send one byte of the response data every 30 seconds
  • The remote HTTP service sends only headers and no body
  • The service can send megabytes of data instead of expected kilobytes
  • Etc.

It would be good to be able to test the behavior of our application when some of those conditions happen.

Cynic tries to help with that testing. Basically it’s a test harness (test double) that can be used to simulate crafty and devious remote systems right from your command line.

Cynic will try hard to cause injury to your system.

It’s goal is to make your system under test cynical.

Installation

$ [sudo] pip install cynic

Or the bleeding edge version from the git master branch:

$ [sudo] pip install git+https://github.com/rspivak/cynic.git#egg=cynic

Quick intro

Start Cynic which in turn will start multiple services on different ports:

$ cynic
INFO     [2012-06-03 23:44:35,603] server: Starting 'HTTPHtmlResponse'   on port 2000
INFO     [2012-06-03 23:44:35,603] server: Starting 'HTTPJsonResponse'   on port 2001
INFO     [2012-06-03 23:44:35,604] server: Starting 'HTTPNoBodyResponse' on port 2002
INFO     [2012-06-03 23:44:35,604] server: Starting 'HTTPSlowResponse'   on port 2003
INFO     [2012-06-03 23:44:35,604] server: Starting 'RSTResponse'        on port 2020
INFO     [2012-06-03 23:44:35,604] server: Starting 'RandomDataResponse' on port 2021
INFO     [2012-06-03 23:44:35,604] server: Starting 'NoResponse'         on port 2022
INFO     [2012-06-03 23:44:35,604] server: Starting 'LogRecordHandler'   on port /tmp/_cynic.sock

Test different services

  1. Connect to the service on port 2020 and get a TCP RST packet right away which causes ‘Connection reset by peer’ message on the command line
$ curl http://localhost:2020
curl: (56) Recv failure: Connection reset by peer
  1. Connect to the service on port 2021 and get back 7 bytes of random data
$ telnet localhost 2021
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
#6
Connection closed by foreign host.
  1. Connect to the service on port 2001 to get the HTTP JSON response
$ curl http://localhost:2001
{"message": "Hello, World!"}

So you got the basic idea. Point your application’s integration points to the Cynic’s services and see how your app reacts.

For more information check the project’s GitHub page at https://github.com/rspivak/cynic

UPDATE [2012-06-04] Added screencast

If you enjoyed this post why not subscribe via email or my RSS feed and get the latest updates immediately. You can also follow me on GitHub or Twitter.

{ 2 comments… read them below or add one }

Alec Munro June 5, 2012 at 7:25 AM

I really like the idea behind this. The primary software I’m working on is a collection of web services, and while our tests are still fairly primitive, something like this testing the interconnections could be very useful.

Thanks

Reply

Ruslan Spivak June 5, 2012 at 7:02 PM

Hey Alec,

You’re welcome.

Cheers.

Reply

Speak your mind

Previous post:

Next post: