Simulating slow or laggy network connections in OS X

A client recently said that their site was loading slowly from remote sites. We got the specification of the network connection used, but I always forget how to do bandwidth limiting and latency simulation on OS X. This is a note for myself so I don't have to go searching again.

Configure a pipe that has the appropriate bandwidth limit and delay.

sudo ipfw pipe 1 config bw 16Kbit/s delay 350ms

Attach it to all traffic going to or from port 80.

sudo ipfw add 1 pipe 1 src-port 80
sudo ipfw add 2 pipe 1 dst-port 80

Now traffic coming from or going to port 80 anywhere is limited by the pipe that you specified. Do your testing and once you get frustrated with slow access to the web remove the rules like so:

sudo ipfw delete 1
sudo ipfw delete 2

Testing CSS @imports

I previously wrote a script to check files that are @imported exist in CSS stylesheets. I've turned that into a set of examples for our RSpec-based test suite. Fire the code into something like spec/views/stylesheets/import_spec.rb.

require File.dirname(__FILE__) + '/../../spec_helper'

describe "Stylesheet" do
  stylesheet_root = File.expand_path(RAILS_ROOT + '/public')
  stylesheets = Dir[File.join(stylesheet_root, "**", "*.css")]

  stylesheets.each do |stylesheet|
    describe stylesheet do
      it "should not @import files that don't exist" do

        missing_imports = []
        imports = File.read(stylesheet).split(/\n|\r/).grep(/\@import url\((.*)\)/)
        imports.each do |import|
          desired_path = import.scan(/url\((["'\ ])?(.*)\1\)/).to_a.first.to_a.last
          desired_root = desired_path[0,1] == "/" ? stylesheet_root : File.dirname(stylesheet)
          filesystem_path = File.expand_path(File.join(desired_root, desired_path))
          if !File.exists?(filesystem_path)
            missing_imports << { :path => filesystem_path, :directive => import }
          end
        end

        if missing_imports.any?
          exception = []
          missing_imports.each do |import|
            exception << "Missing @import file (#{import[:path]}) required for #{import[:directive]}"
          end
          raise exception.join("\n")
        end
      end
    end
  end
end

Getting started with Story Driven Development for Rails with Cucumber

I've been hearing about Story Driven Development (SDD) for a while but I haven't tried it out because I was under the impression that there was a huge amount to learn and setup before I could get going. I'm not sure if that used to be true, but I started using Cucumber yesterday and it was really easy.

Install and configure

You'll need to install a bunch of RubyGems.

sudo gem install nokogiri term-ansicolor treetop diff-lcs hpricot cucumber

Install Cucumber into your Rails app.

ruby script/generate cucumber

Install WebRAT. Unfortuantely this doesn't seem to be available as a RubyGem. If you're using Git then install this as a submodule instead. We're not so I clone the repository then svn add it.

git clone git://github.com/brynary/webrat.git vendor/plugin/webrat

Writing your first story

Stories have three components: a business value, the role of a person that uses the feature and some description of the feature.

In order to [do something with business value]
As [role]
Should [describe the feature]

An example might be the ability to order a pizza from the online ordering system of a pizza delivery company.

Feature: Order Pizza
  In order to get some hot, tasty pizza
  A hungry pizza lover
  Should be able to order pizza

Next we need to define some scenarios. Scenarios are things that can happen during the story. Most pizza places aren't open 24 hours a day so two simple scenarios are (1) the pizza shop is closed, and (2) the pizza shop is open.

  Scenario: The pizza shop is closed
    Given the pizza shop is closed
    And I am on the home page
    And I click "Feed Me!"
    Then I should see "Sorry, the shop is closed"

  Scenario: The pizza shop is open
    Given the pizza shop is open
    And I am on the home page
    And I click "Feed Me!"
    Then I should see "Your pizza will be with you soon"

The above description should go in a file called something like features/order_pizza.feature where it is lovely and version controlled and safe.

So, we now have a story that describes how a feature should behave. How does that get turned into acceptance tests? Well, you could pass these descriptions off to your testing team, or you could turn them into part of your test suite.

Automated tests: better than cake

You might notice that when installing Cucumber you got the directory features/steps. That's where you tell your test suite how to understand your stories. There are already two files here: common_webrat.rb which gives your test suite a few funky things like the ability to click links and env.rb which does pretty much the same stuff as spec/spec_helper.rb except for Cucumber. You can ignore env.rb, but common_webrat.rb will provide a few examples of how to start writing story steps.

Create a new file, order_pizza_steps.rb. This is where you define the steps involved in ordering pizza. It's pretty much just regular expressions which match each line of a scenario to some Ruby code.


Given /the pizza shop is open/ do
  PizzaShop.open = true
end

Given /the pizza shop is closed/ do
  PizzaShop.open = false
end

And /I am on the home page/ do
  visits "/"
end

That's all we need to do. The common WebRAT steps provide the necessary mapping for clicking buttons and checking for feedback.

Running your stories

This is pretty simple: run rake features. You should get some rather pretty coloured output, and if anything has gone wrong Cucumber is pretty good at suggesting ways to fix it.

Found this article useful?

If you enjoyed this article I'd appreciate recommendations at Working with Rails.

About the boy

A picture of Craig in grayscale

Craig Webster is a software engineer living in London. He usually works with Ruby although sometimes he sneaks in some Erlang or JavaScript. He's into rock climbing, snowboarding, skating, photography and fencing. Yes, this does mean he has a sword.

Near here you'll find Craig's homepage, contact details, PGP key and keysigning policy, and talks.

Licence

The entire content of this blog is public domain. Use it however you fancy. You don't even need to attribute it to me, although it would be nice if you did. Just don't sue me and we'll all be happy.

I Work With Rails

Recommend Me

My Travels

I go places. Do you go places too? Let's meet up!.