How’s it used?

RFuzz is really easy to use for just basic HTTP requests and running simple tests. It’s even easier if you follow the REST paradigm.

The following are the examles that come with the gem.

hpricot_pudding.rb

Simple client that lets you search google from the command line. Run it with:

ruby hpricot_pudding.rb "ruby zed"

and it will return all the results printed out. (requires hpricot)

require 'rubygems' require 'hpricot' require 'rfuzz/session' include RFuzz agent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Firefox/1.5.0.4" google = HttpClient.new("www.google.com", 80) r = google.get("/search", :head => {"User-Agent" => agent}, :query => {"q" => ARGV[0], "hl" => "en", "btnG" => "Google Search"}) if r.http_status != "200" puts "Wrong Status: #{r.http_status}?" else doc = Hpricot(r.http_body) (doc/:a).each do |link| if link.attributes["class"] == "l" puts link.attributes["href"] puts " -- " + link.children.join end end end

kill_routes.rb

Demonstrates hitting a Ruby on Rails application with randomly generated long and insanely long URIs to see if you can choke the Rails routes system. When running under Mongrel you’ll find that Mongrel’s explicit limit of 512 characters on URIs protects Rails quite well.

It is also saving the results in the runs.csv and counts.csv files so you can analyze them after the run. It assumes the rails application is running on port 3000.

require 'rfuzz/session' include RFuzz s = Session.new :host => "localhost", :port => 3000 s.run 10, :save_as => ["runs.csv","counts.csv"] do |c,r| len = r.num(90) + 1 s.count :len, len uris = r.uris(ARGV[0].to_i,len) uris.each do |u| s.count_errors(:legal) do # first sample for legal uris resp = c.get(u) s.count resp.http_status end # next sample for illegal uris s.count_errors(:illegal) do resp = c.get(u * 512) s.count resp.http_status end end end

perftest.rb

A simplistic performance test that actually tests the speed of processing a full request/response cycle by both the server and RFuzz. This isn’t how fast your server is, but how fast RFuzz and your server are when combined.

This sample is more low level not using the RFuzz::Session class and its DSL (which would simplify this code).

require 'rfuzz/client' require 'rfuzz/stats' include RFuzz if ARGV.length != 4 STDERR.puts "usage: ruby perftest.rb host port uri count" exit 1 end host, port, uri, count = ARGV[0], ARGV[1], ARGV[2], ARGV[3].to_i codes = {} cl = HttpClient.new(host, port, :notifier => StatsTracker.new) count.times do begin resp = cl.get(uri) code = resp.http_status.to_i codes[code] ||= 0 codes[code] += 1 rescue Object end end puts cl.notifier.to_s puts "Status Codes: #{codes.inspect}"

REST Client Sample

I used this in a project recently in order to do simple REST queries against a backend service:

class RESTClientError < Exception; end class RESTClient def initialize(host,port, base="") @host, @port = host, port @base = base @client = RFuzz::HttpClient.new(host,port) end def target_uri(symbol) uri = @base + "/" + symbol.to_s.tr("_","/") end def method_missing(symbol, *args) res = @client.get(target_uri(symbol), :query => (args[0] || {})) raise_error_if(res.http_status != "200", "Invalid Status #{res.http_status} from server #{@host}:#{@port}") return REXML::Document.new(res.http_body).root end def raise_error_if(test, msg) raise RESTClientError.new(msg) if test end end

It basically takes any function call of the format client.call_that_thing :with => "this" and translates it to the request ”/call/that/thing?with=this” then does a GET request. If the response is not 200 it throws an error, otherwise it uses REXML to make into a document for the caller to work with.