Debugging Net::HTTP and Ruby OAuth

Posted on 23 Feb 2011

There’s a handy method on Net::HTTP which allows you to send detailed debugging information (including request and response headers/bodies) to a stream. The OAuth gem uses Net::HTTP and it’s easy to get at. For example, you can write debug info to your web server’s log like this:

# Create a consumer
consumer = OAuth::Consumer.new("key", "secret", :site => "https://agree2")

# Enable debugging
consumer.http.set_debug_output($stderr)

# Do stuff
request_token = consumer.get_request_token(:oauth_callback => "http://example.com")

1Password Chromium Extension

Posted on 06 Jan 2011

1Password doesn’t provide a way to install its extension in Chromium. Instead, you can install it from here:

http://aws.cachefly.net/aws/dmg/1PW3/English/OnePasswordChrome.crx

Running MIT Scheme in Emacs on OS X

Posted on 18 Nov 2010
  1. Download and install MIT Scheme.

  2. Create a symbolic link to the Scheme binary, something like this:

     cd /usr/local/bin
     sudo ln -s /Applications/mit-scheme.app/Contents/Resources/mit-scheme scheme
  3. Set the MITSCHEME_LIBRARY_PATH environment variable in Emacs. I’m using the Emacs Starter Kit so I do this in ~/.emacs.d/paulhorsfall.el, you’ll need to put it somewhere appropriate for your set-up. You might also want to set this in your shell if you’d like to run scheme there.

     ;; MIT Scheme
     (setenv "MITSCHEME_LIBRARY_PATH"  "/Applications/mit-scheme.app/Contents/Resources")

With that, you can now do M-x run-scheme to start a scheme interpreter. You can switch a buffer to Scheme mode using M-x scheme-mode, and from there you can do C-x C-e to send the expression to the left of the point to the Scheme interpreter for evaluation.

Integration Testing Webhooks

Posted on 19 Aug 2010

The Problem

Testing aspects of your web app that use an API that employs webhooks/callbacks can be awkward, as typically your development environment is not accessible by the API provider. You can expose your local server to the internet by creating an SSH tunnel, but when it comes to testing it’s less than ideal if you have to manually start the tunnel, and perhaps perform some config with the API provider before you can run the tests. A lot of the knowledge about the environment required to run the test is kept outside of the test itself, therefore it is not as automated as it could be. If you bother to write the test, you probably won’t run it.

A Solution

The solution to this problem (at least for one project I’m working on) is a few Cucumber steps and a simple Ruby wrapper around the wonderful localtunnel gem, which makes it simple to create throw-away SSH tunnels which are perfect for testing. Localtunnel does all of the heavy lifting here, the Cucumber steps simply start a tunnel once per test run, and in this example login to a Google Checkout sandbox account to configure the callback URL based on the host which is dynamically assigned to you each time you run localtunnel. (You don’t have to use Cucumber for this, you could easily adapt this to straight up webrat/capybara or whatever it is you’re using.)

First, here’s a wrapper around the localtunnel binary that makes it simple to start a new tunnel and fetch the hostname which is forwarded to your machine. (It uses PTY, so I imagine it won’t work on Windows.) In a Rails app, you could drop this in lib/local_tunnel.rb.

require 'pty'
require 'singleton'

class LocalTunnel
  include Singleton
  attr_accessor :url, :pid

  def initialize
    @started = false
  end

  def start(port = 8080)
    unless @started
      r, w, pid = PTY.spawn("localtunnel #{port}")
      self.pid = pid

      output = ""
      r.each do |line|
        output << line
        break if line =~ /accessible from (.*) \.\.\./
      end
      self.url = $1

      if url
        @started = true
      else
        raise "Could not start SSH tunnel:\n\n#{output}\n"
      end
    end
  end

  def started?
    @started
  end
end

With that, writing a Cucumber step to setup the tunnel is trivial:

Given /^my test environment is available via an SSH tunnel$/ do
  LocalTunnel.instance.start(9887)
end

And here’s an example of some steps to configure Google Checkout. Clearly this is somewhat app specific, but you get the idea. (I’m setting a flag here so that this is only performed by the first feature that actually needs it. If there’s a cleaner way to do this please let me know.)

Given /^the Google Checkout Sandbox is configured to callback to my test environment$/ do
  unless google_checkout_sandbox_configured?
    visit "https://sandbox.google.com/checkout/sell/"
    And %q{I login to Google as "me@gmail.com" with password "mypassword"}
    click_link "Settings"
    click_link "Integration"
    fill_in "apiURL", :with => "#{LocalTunnel.instance.url}/google_checkout"
    click_button "Save"
    click_link "Sign out"
    self.google_checkout_sandbox_configured = true
  end
end

When /^I login to Google as "([^\"]*)" with password "([^\"]*)"$/ do |login, password|
  within_frame "login" do
    fill_in 'Email', :with => login
    fill_in 'Passwd', :with => password
    click_button "Sign in and continue"
  end
end

# A flag used to track wether we've configured the Google Sandbox to use the SSL
# tunnel URL across scenarios.
module GoogleCheckoutHelpers
  def google_checkout_sandbox_configured=(value)
    self.class.class_eval { @google_checkout_sandbox_configured = value }
  end

  def google_checkout_sandbox_configured?
    self.class.class_eval { @google_checkout_sandbox_configured }
  end
end

World(GoogleCheckoutHelpers)

With that in place, you might end up with a scenario that looks a little like this:

Feature: Paying with Google Checkout

  Background:
    Given my test environment is available via an SSH tunnel
    And the Google Checkout Sandbox is configured to callback to my test environment

  Scenario: Paying with Google Checkout
    Given I have some products in my cart
    When I press "Google Checkout"
    And I login to Google as "customer" with password "password"
    And I press "bottomBuyButton"
    Then I should see "Your order has been sent."
    Given I am logged in as an admin
    And I am on the admin orders page
    And I click view on the 1st order
    And I wait until I see "Current status: Paid"
    Then I should see "Current status: Paid"

This pretty much takes care of the problem as I originally outlined it. The only slight snag is that the first time you use localtunnel you need to pass it the path to your public SSH key. If a developer who hasn’t used localtunnel before tries to run our feature, the SSH tunnel won’t be created and the feature will fail. To help them along, they’ll see an instruction to run something like localtunnel -k /Users/jeff/.ssh/id_rsa.pub included in the test’s output.

Installing _why's Bloopsaphone on OS X

Posted on 13 Feb 2010

Inspired by a recent rush of nostalgia, I finally got around to playing with _why's Bloopsaphone recently. Give or take the odd crash, it works pretty well with whichever version of PortAudio MacPorts gave me.

sudo port install portaudio
sudo gem install bloopsaphone -- --with-opt-lib=/opt/local/lib --with-opt-include=/opt/local/include

There are a couple of Bloopsaphone tunes by freQvibez which are worth looking at if you want to hear the kind of thing you can create with this.