Skip to content
Browse files

Committing

  • Loading branch information...
0 parents commit 2f5722574f3540f6a0b170d3ec9b5bb25c6c2e85 Joe Ferris committed Oct 30, 2008
Showing with 253 additions and 0 deletions.
  1. BIN .Rakefile.swp
  2. +37 −0 Rakefile
  3. +17 −0 assert_performs.gemspec
  4. +50 −0 lib/assert_performs.rb
  5. +1 −0 rails/init.rb
  6. +125 −0 test/assert_performs_test.rb
  7. +23 −0 test/httperf_output.erb
BIN .Rakefile.swp
Binary file not shown.
37 Rakefile
@@ -0,0 +1,37 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/gempackagetask'
+require 'date'
+
+test_files_pattern = 'test/**/*_test.rb'
+Rake::TestTask.new do |t|
+ t.libs << 'lib'
+ t.pattern = test_files_pattern
+ t.verbose = false
+end
+
+desc "Run the test suite"
+task :default => :test
+
+spec = Gem::Specification.new do |s|
+ s.name = "assert_performs"
+ s.summary = "Easily add performance sanity checks using Test::Unit and a staging server"
+ s.email = %w(jferris@thoughtbot.com dcroak@thoughtbot.com)
+ s.homepage = "http://github.com/thoughtbot/assert_performs"
+ s.description = "Easily add performance sanity checks using Test::Unit and a staging server"
+ s.authors = ["Dan Croak", "Joe Ferris"]
+ s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
+ s.version = '1.0.0'
+end
+
+Rake::GemPackageTask.new spec do |pkg|
+ pkg.need_tar = true
+ pkg.need_zip = true
+end
+
+desc "Generate a gemspec file"
+task :gemspec do
+ File.open("#{spec.name}.gemspec", 'w') do |f|
+ f.write spec.to_ruby
+ end
+end
17 assert_performs.gemspec
@@ -0,0 +1,17 @@
+Gem::Specification.new do |s|
+ s.name = %q{assert_performs}
+ s.version = "1.0.0"
+
+ s.specification_version = 2 if s.respond_to? :specification_version=
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Dan Croak", "Joe Ferris"]
+ s.date = %q{2008-10-30}
+ s.description = %q{Easily add performance sanity checks using Test::Unit and a staging server}
+ s.email = ["jferris@thoughtbot.com", "dcroak@thoughtbot.com"]
+ s.files = ["Rakefile", "lib/assert_performs.rb", "test/assert_performs_test.rb", "test/httperf_output.erb"]
+ s.homepage = %q{http://github.com/thoughtbot/assert_performs}
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.0.1}
+ s.summary = %q{Easily add performance sanity checks using Test::Unit and a staging server}
+end
50 lib/assert_performs.rb
@@ -0,0 +1,50 @@
+class Test::Unit::TestCase
+
+ # httperf --server jobs.local
+ # --method=GET
+ # --uri="/naturejobs/science"
+ # --timeout 1
+ # --num-conns=10
+
+ cattr_accessor :performance_server
+
+ # Example:
+ # assert_performs :get, user_path, :rate => 2,
+ # :timeout => 5
+ # :id => 1 # extra params
+ def assert_performs(method, uri, params = {})
+ timeout = params.delete(:timeout)
+ rate = params.delete(:rate)
+
+ query = "?#{params.to_query}"
+
+ args = []
+ args << "--server=#{Test::Unit::TestCase.performance_server}"
+ args << "--method=#{method.to_s.upcase}"
+ args << "--uri='#{uri}#{query}'"
+ args << "--timeout=#{timeout}"
+ args << "--num-conns=3"
+
+ command = "httperf #{args.join(' ')}"
+ output = `#{command}`
+ result = parse_httperf_output(output)
+
+ assert_equal 0, result[:errors],
+ "One or more connections failed or timed out"
+ assert result[:rate] >= rate,
+ "Expected at least #{rate} req/s, but got #{result[:rate]}"
+ end
+
+ def parse_httperf_output(output)
+ result = {}
+
+ match = output.match(%r{Request rate: ([\d.]+) req/s})
+ result[:rate] = match[1].to_f
+
+ match = output.match(%r{Errors: total ([\d]+)})
+ result[:errors] = match[1].to_i
+
+ result
+ end
+
+end
1 rails/init.rb
@@ -0,0 +1 @@
+require 'lib/assert_performs'
125 test/assert_performs_test.rb
@@ -0,0 +1,125 @@
+require 'test/unit'
+require 'rubygems'
+require 'shoulda'
+require 'erb'
+require 'active_support'
+require 'active_support/core_ext'
+
+$: << File.join(File.dirname(__FILE__), '..', 'lib')
+require 'assert_performs'
+
+class AssertPerformsTest < Test::Unit::TestCase
+
+ def setup
+ @command = 'NO COMMAND WAS RUN'
+ end
+
+ def `(command)
+ @command = command
+ @output
+ end
+
+ context "when setting the performance server" do
+ setup do
+ @old_value = Test::Unit::TestCase.performance_server
+ @new_value = 'test.local'
+ Test::Unit::TestCase.performance_server = @new_value
+ end
+
+ teardown do
+ Test::Unit::TestCase.performance_server = @old_value
+ end
+
+ should "return the new value" do
+ assert_equal @new_value, Test::Unit::TestCase.performance_server
+ end
+ end
+
+ context "when asserting with valid arguments" do
+ setup do
+ @old_performance_server = Test::Unit::TestCase.performance_server
+ Test::Unit::TestCase.performance_server = 'test.local'
+
+ @request_rate = 100
+ @errors = 0
+ @output = httperf_output
+ assert_performs :get, '/whatever', :rate => 2, :timeout => 2, :id => 1
+ end
+
+ teardown do
+ Test::Unit::TestCase.performance_server = @old_performance_server
+ end
+
+ should "Use the correct performance server in the generated command" do
+ assert_match /--server=test\.local/, @command
+ end
+
+ should "use the specified HTTP method in the generated command" do
+ assert_match /--method=GET/, @command
+ end
+
+ should "use the specified URI in the generated command" do
+ assert_match /--uri='\/whatever?[^']*'/, @command
+ end
+
+ should "append parameters to the URI in the generated command" do
+ assert_match /\?id=1/, @command
+ end
+
+ should "use the specified timeout in the generated command" do
+ assert_match /--timeout=2/, @command
+ end
+
+ should "use the correct number of connections in the generated command" do
+ assert_match /--num-conns=3/, @command
+ end
+ end
+
+ context "when a request causes an error" do
+ setup do
+ @request_rate = 100
+ @errors = 1
+ @output = httperf_output
+ end
+
+ should "fail" do
+ assert_raise(Test::Unit::AssertionFailedError) do
+ assert_performs :get, '/', :rate => @request_rate - 1, :timeout => 2
+ end
+ end
+ end
+
+ context "with an unacceptable request rate and no errors" do
+ setup do
+ @request_rate = 0
+ @errors = 0
+ @output = httperf_output
+ end
+
+ should "fail" do
+ assert_raise(Test::Unit::AssertionFailedError) do
+ assert_performs :get, '/', :rate => @request_rate + 1, :timeout => 2
+ end
+ end
+ end
+
+ context "with an acceptable request rate and no errors" do
+ setup do
+ @request_rate = 100
+ @errors = 0
+ @output = httperf_output
+ end
+
+ should "pass" do
+ assert_nothing_raised do
+ assert_performs :get, '/', :rate => @request_rate - 1, :timeout => 2
+ end
+ end
+ end
+
+ def httperf_output
+ output_file = File.join(File.dirname(__FILE__), 'httperf_output.erb')
+ template = File.read(output_file)
+ ERB.new(template).result(binding)
+ end
+end
23 test/httperf_output.erb
@@ -0,0 +1,23 @@
+httperf --timeout=1 --client=0/1 --server=server --port=80 --uri=/uri/to/test --send-buffer=4096 --recv-buffer=16384 --method=GET --num-conns=1 --num-calls=1
+Maximum connect burst length: 0
+
+Total: connections 1 requests 1 replies 1 test-duration 0.173 s
+
+Connection rate: 5.8 conn/s (172.7 ms/conn, <%= '<=' %>1 concurrent connections)
+Connection time [ms]: min 172.7 avg 172.7 max 172.7 median 172.5 stddev 0.0
+Connection time [ms]: connect 0.2
+Connection length [replies/conn]: 1.000
+
+Request rate: <%= @request_rate %> req/s (172.7 ms/req)
+Request size [B]: 138.0
+
+Reply rate [replies/s]: min 0.0 avg 0.0 max 0.0 stddev 0.0 (0 samples)
+Reply time [ms]: response 172.5 transfer 0.0
+Reply size [B]: header 575.0 content 133.0 footer 0.0 (total 708.0)
+Reply status: 1xx=0 2xx=0 3xx=1 4xx=0 5xx=0
+
+CPU time [s]: user 0.04 system 0.12 (user 21.4% system 70.6% total 92.0%)
+Net I/O: 4.8 KB/s (0.0*10^6 bps)
+
+Errors: total <%= @errors %> client-timo 0 socket-timo 0 connrefused 0 connreset 0
+Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

0 comments on commit 2f57225

Please sign in to comment.
Something went wrong with that request. Please try again.