Tagged: coffeescript

Continuous Integration Using Bill Cosby

Cosbybot in the Silly Face Society lobby
The Silly Face Society lobby featuring a very special guest. It isn’t Chris Young.

The Silly Face Society is our soon-to-be-released social iOS game where you advance in stature by sending silly faces and having friends guess the type of face you made. In this post, I’ll cover how we use Bill Cosby to continuously test our server code.

Testing and lazyness

Arg! Team made up of two part-timers and it is apparent that neither of us know anything about project management. We can’t scope, our estimates are off by an order of magnitude, and we refuse to cut features in the interests of launching. As a result Chris is often practicing “scope by art” while I practice “design by code”. A stark contrast to my old enterprise day job that makes me grind my teeth when it comes to writing tests. So, I decided early in this project not to write any tests, server or client. And our server uses a notoriously soupy dynamic language. Don’t do as I did.

Besides the guilt, one thought still kept me up at night: what if I unwittingly make a small change that completely breaks our iOS experience?

Enter Cosbybot

When I was younger, I would spend a lot of time on IRC interacting with Eggdrop trivia bots. Recently, it occurred to me: I can I fool myself into writing tests by calling them bots instead. My “test suite” would be a bot that could be challenged by players using our iOS client. And who better to make silly faces than Bill Cosby?

As I wrote Cosbybot, it occurred to me that bots come with some other benefits:

  • Whenever I need to demo to someone, I always have someone to play with that responds quickly.
  • Bots can be operated outside the server: if the server is acting oddly towards our users then the bot will catch it.
  • Writing a “clean room” client outside of my iOS app ensures I didn’t make bad assumptions.

Mechanics of Cosbybot

The following is a brief visual summary of “testing” the Silly Face Society by playing against Cosbybot:

1. A member of the Silly Face Society starts a game with Cosbybot
2. The member sends Cosbybot a silly face
3. Cosbybot guesses randomly at the silly face and taunts the submitter.
4. Cosbybot sends his own picture to be guessed

Cosbybot is a real account (with a login) that uses programmatic client. I implemented a simple state machine that advances along WAITING SUBMIT -> GUESSING -> SUBMITTING -> WAITING GUESS. Every thirty seconds, Cosbybot scans for all open rounds and tries to advance them by a step in the state machine, submitting a photo of Bill Cosby when required. If an error occurs (bad response code, bad login, bad serialization, unexpected format, server down, etc.) then an error is logged at “fatal” which fires me an e-mail using node’s winston module.

Cosbybot acts without internal knowledge and I keep it in an external script that interacts with the Silly Face Society server over HTTP (via node’s request module). The source for the bot is a bit too long for this post, but is available in this gist. Here’s the run loop:

fe = forwardError = (cb, fn) -> (err) ->
  return cb(err) if err?
  fn Array::slice.call(arguments, 1)...

execute = ->
  login fe reportError, ->
    refresh fe reportError, (responseJson) ->
      {rankName, id, monocles} = responseJson.currentPlayer
      winston.info "#{botName} (#{id}) rank: '#{rankName}' - #{monocles} monocles"
      async.forEachSeries responseJson.rounds,
        (round, callback) ->
          switch actionState(id, round)
            when ACTION_STATES.YOU_SUBMIT then submitPhoto round, callback
            when ACTION_STATES.YOU_GUESS
              guessUntilClosed round, fe callback, ->
                taunt round, callback
            else callback()
        fe reportError, -> reexecute()

To understand this properly, see the context in the gist.

Continuity in Continuous Integration

Urkelbot and Cosbybot together at long last.

So far, all of our “tests” require a human to send a submission or guess a photo. Fortunately, there is a quick way of removing the human element: introduce one more bot.

I created another Silly Face Society account named “Urkelbot” and manually challenged Cosbybot to a round. I then booted copies of Cosbybot and Urkelbot on our production and dev servers. In each scan, Urkelbot’s state machine is advanced by Cosbybot (and vice-versa). Since the states are circular, we get continuous external testing of each server build. If I introduce a regression that prevents the game from being played, one of the bots will send me an e-mail alerting me of the failure.

And there you have it: Bill Cosby tests our code all day. If you like Bill Cosby and silly faces then be the first to try The Silly Face Society on the iPhone.

P.S. how was this show possibly ever on television?

Connection Pooling with node-postgres

Update on June 24, 2012: I submitted a patch to node-pool that exposes this pattern through a method called pooled on generic connection pools. I’ve updated the code samples below to include the more robust pattern. Take a look for Pooled function decoration in node-pool’s README.md for more information.

Documentation on node-postgres’ connection pooling is a little sparse. It is built-in but usage is somewhat unclear. Below is a minimally intrusive way to introduce it into an app.

node-postgres’ connection pooling works through the connect function on the module object:

pg = require 'pg'
pg.connect connectionString, (err, pgClient) ->
  return console.log "Error! #{err}" if err?
  # use pgClient

pgClient above is a pooled client. When a drain event occurs on the client, it is automatically returned to the pool: drain events generally occur after query has been executed on the client, unless you have suppressed drain events during a transaction. For full information, see the node-postgres documentation

Let’s assume you have a data access module with methods like this:

exports.findWidget = findWidget = (id, callback) -> ...
exports.transactedWidget = transactedWidget = (widgetSauce, callback) -> ...

The obvious way to incorporate connection pooling is something like:

pg = require 'pg'
connectionString = "tcp://postgres:postgres@localhost/dummy_db"
exports.findWidget = findWidget = (id, callback) ->
  pg.connect connectionString, (err, pgClient) ->
    return callback(err) if err?
    ... #Use pgClient to find

exports.transactedWidget = transactedWidget = (widgetSauce, callback) ->
  pg.connect connectionString, (err, pgClient) ->
    return callback(err) if err?
    ... #Use pgClient and do some transaction stuff

Frown town: three lines of useless boilerplate to every exported method in the data layer. Furthermore, trying to re-use methods in a transaction context is impossible. We can do better – create a new file called pg_pool.coffee with the following:

pg = require 'pg'

module.exports = pooler =
   #Get a connection from the pool
  acquire: (callback) -> pg.connect "tcp://postgres:postgres@localhost/dummy_db", callback

  #Decorate a function to use the de-pooled connection as a first argument
  pooled: (fn) -> ->
    callerCallback = arguments[arguments.length - 1]
    callerHasCallback = typeof callerCallback == 'function'
    callerArgs = Array::slice.call(arguments, 0, if callerHasCallback then -1 else undefined)

    pooler.acquire (err, pgClient) ->
      return (callerCallback err if err?) if err?
      callerArgs.push ->
        callerCallback.apply(null, arguments) if callerHasCallback
      fn pgClient, callerArgs...

Also available as gist. The pooled method creates a python-style decorator that will wrap data access methods in a connection pool. Furthermore, the client is kept out of the pool until the callback is executed (this is what pgClient.pauseDrain() and pgClient.resumeDrain() do in the above example). Using this, we can replace the data layer code with:

{pooled} = require './pg_pool'
exports.findWidget = pooled findWidget = (pgClient, id, callback) ->
 ... #Use pgClient to find widget
exports.transactedWidget = pooled transactedWidget = (pgClient, widgetSauce, callback) -> 
 ... #Use pgClient to do some jazz

In addition to brevity, this enabled nested method calls in transaction-context. The non-exported versions of the methods accept a pgClient parameter. For example, if transactedWidget needed to call findWidget in a transaction:

{pooled} = require 'pg_pool'
exports.findWidget = pooled findWidget = (pgClient, id, callback) ->
 ... #Use pgClient to find widget
exports.transactedWidget = pooled transactedWidget = (pgClient, widgetSauce, callback) -> 
 pgClient.query "BEGIN", (err) ->
   return callback(err) if err?  
   findWidget pgClient, "123", (err, widget) ->
     return callback(err) if err?
     pgClient.query "COMMIT", (err) ->
       callback(err, widget)

Not the prettiest code, but it beats having to write two versions of each method. Since we are using the pooled decorator, we can guarantee that the pgClient is stable for duration of this transaction.