tourbus 0.1.5 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -45,7 +45,7 @@ better name, these are called Tours.
45
45
  * Make a folder called tours and put a file in it called simple.rb. In
46
46
  it write:
47
47
 
48
- class Simple < Tour
48
+ class Simple < Tourist
49
49
  def test_homepage
50
50
  visit "http://#{@host}/"
51
51
  assert_contain "My Home Page"
@@ -53,7 +53,7 @@ better name, these are called Tours.
53
53
  end
54
54
 
55
55
  * Files in ./tours should have classes that match their names. E.g.
56
- "class BigHairyTest < Tour" belongs in ./tours/big_hairy_test.rb
56
+ "class BigHairyTest < Tourist" belongs in ./tours/big_hairy_test.rb
57
57
 
58
58
  * Think Test::Unit. test_* methods will be found automagically.
59
59
  setup() and teardown() methods will be executed at the appropriate
data/bin/tourbus CHANGED
@@ -18,15 +18,15 @@ config[:rand] ||= nil
18
18
 
19
19
  opts = Trollop.options do
20
20
  opt :host, "Remote hostname to test", :default => config[:host]
21
- opt :concurrency, "Number of simultaneous runs to perform", :type => :integer, :default => config[:concurrency]
22
- opt :number, "Number of times to run the tour (in each concurrent step, so -c 10 -n 10 will run the tour 100 times)", :type => :integer, :default => config[:number]
23
- opt :list, "List tours and runs available. If tours or runs are included, filters the list", :type => :boolean, :default => nil
21
+ opt :concurrency, "Number of simultaneous tourists to run", :type => :integer, :default => config[:concurrency]
22
+ opt :number, "Number of times to run the tourist (in each concurrent step, so -c 10 -n 10 will run the tourist 100 times)", :type => :integer, :default => config[:number]
23
+ opt :list, "List tourists and tours available. If tourists or tours are included, filters the list", :type => :boolean, :default => nil
24
24
  opt :rand, "Random seed", :type => :integer, :default => config[:rand]
25
25
  opt :tests, "Test name(s) filter. The name of the test to run (use --list to see the test names). Use commas, no spaces, for mulitple names", :type => :string, :default => nil
26
26
  end
27
27
 
28
- tours = if ARGV.empty?
29
- Tour.tours
28
+ tourists = if ARGV.empty?
29
+ Tourist.tourists
30
30
  else
31
31
  ARGV
32
32
  end
@@ -34,13 +34,13 @@ tours = if ARGV.empty?
34
34
  srand opts[:rand] || Time.now.to_i
35
35
 
36
36
  if opts[:list]
37
- Tour.tours(ARGV).each do |tour|
38
- puts tour
39
- puts Tour.tests(tour).map {|test| " #{test}"}
37
+ Tourist.tourists(ARGV).each do |tourist|
38
+ puts tourist
39
+ puts Tourist.tours(tourist).map {|test| " #{test}"}
40
40
  end
41
41
  else
42
42
  opts[:tests] = opts[:tests].split(',') if opts[:tests]
43
43
 
44
- TourBus.new(opts[:host], opts[:concurrency], opts[:number], tours, opts[:tests]).run
44
+ TourBus.new(opts[:host], opts[:concurrency], opts[:number], tourists, opts[:tests]).run
45
45
  end
46
46
 
data/bin/tourproxy ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # This proxy logger logs x-amf traffic, and is stolen with gratitude from http://altentee.com/2008/performance-testing-flex-remoting-amf-with-jmeter/
3
+
4
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'tour_proxy'))
5
+
6
+ options = {}
7
+
8
+ proxy = TourProxy.new options
9
+ trap "INT" do proxy.shutdown end
10
+ proxy.start
@@ -7,7 +7,7 @@ Silly little contact app to show you how to tour a website.
7
7
  In addition to tourbus, you will need Sinatra to run
8
8
  this app.
9
9
 
10
- sudo gem install sinatra
10
+ gem install sinatra
11
11
 
12
12
  = Contact App
13
13
 
@@ -1,19 +1,20 @@
1
- class Simple < Tour
2
- def test_home
3
- visit "/"
1
+ require 'ruby-debug'
2
+ class Simple < Tourist
3
+ def tour_home
4
+ visit "#{@host}/"
4
5
  assert_contain "If you click this"
5
6
 
6
7
  click_link "Enter Contact"
7
- assert_match /\/contacts/, current_page.url
8
+ assert_match /\/contacts/, current_url
8
9
  end
9
10
 
10
- def test_contacts
11
- visit "/contacts"
12
-
11
+ def tour_contacts
12
+ visit "#{@host}/contacts"
13
+
13
14
  fill_in "first_name", :with => "Joe"
14
15
  fill_in "last_name", :with => "Tester"
15
- click_button
16
-
16
+ click_button
17
+
17
18
  assert_contain "Tester, Joe"
18
19
  end
19
20
  end
data/lib/common.rb CHANGED
@@ -13,16 +13,25 @@ gem 'faker', '>= 0.3.1'
13
13
 
14
14
  # TODO: I'd like to remove dependency on Rails. Need to see what all
15
15
  # we're using (like classify) and remove each dependency individually.
16
- require 'activesupport'
16
+ begin
17
+ require 'activesupport'
18
+ rescue Exception
19
+ require 'active_support/all'
20
+ end
17
21
 
18
22
  require 'monitor'
19
23
  require 'faker'
20
24
  require 'tour_bus'
21
25
  require 'runner'
22
- require 'tour'
26
+ require 'tourist'
23
27
 
28
+ # Our common base class for exceptions
24
29
  class TourBusException < Exception; end
25
30
 
31
+ # The common base class for all exceptions raised by Webrat.
32
+ class WebratError < StandardError ; end
33
+
34
+
26
35
  def require_all_files_in_folder(folder, extension = "*.rb")
27
36
  for file in Dir[File.join('.', folder, "**/#{extension}")]
28
37
  require file
data/lib/file.rb ADDED
@@ -0,0 +1,11 @@
1
+ class File
2
+ # Hides all that lovely expand/join/dirname(__FILE__, path) crap
3
+ #
4
+ # E.g.: require File.here("../lib/pants")
5
+ #
6
+ # Splatty version for the OS Agnosts out there:
7
+ # require File.here(%w[.. lib pants])
8
+ def self.here(*args)
9
+ p = File.expand_path(File.join(File.dirname(caller.first.split(':')[0]), *args))
10
+ end
11
+ end
data/lib/runner.rb CHANGED
@@ -1,40 +1,37 @@
1
1
  require 'monitor'
2
2
  require 'common'
3
3
 
4
- # The common base class for all exceptions raised by Webrat.
5
- class WebratError < StandardError ; end
6
-
7
4
  class Runner
8
- attr_reader :host, :tours, :number, :runner_type, :runner_id
5
+ attr_reader :host, :tourists, :number, :runner_type, :runner_id
9
6
 
10
- def initialize(host, tours, number, runner_id, test_list)
11
- @host, @tours, @number, @runner_id, @test_list = host, tours, number, runner_id, test_list
7
+ def initialize(host, tourists, number, runner_id, tour_list)
8
+ @host, @tourists, @number, @runner_id, @tour_list = host, tourists, number, runner_id, tour_list
12
9
  @runner_type = self.send(:class).to_s
13
10
  log("Ready to run #{@runner_type}")
14
11
  end
15
12
 
16
13
  # Dispatches to subclass run method
17
- def run_tours
18
- log "Filtering on tests #{@test_list.join(', ')}" unless @test_list.to_a.empty?
19
- tours,tests,passes,fails,errors = 0,0,0,0,0
14
+ def run_tourists
15
+ log "Filtering on tours #{@tour_list.join(', ')}" unless @tour_list.to_a.empty?
16
+ tourists,tours,passes,fails,errors = 0,0,0,0,0
20
17
  1.upto(number) do |num|
21
18
  log("Starting #{@runner_type} run #{num}/#{number}")
22
- @tours.each do |tour_name|
19
+ @tourists.each do |tourist_name|
23
20
 
24
- log("Starting run #{num}/#{number} of Tour #{tour_name}")
25
- tours += 1
26
- tour = Tour.make_tour(tour_name,@host,@tours,@number,@runner_id)
27
- tour.before_tour
21
+ log("Starting run #{num}/#{number} of Tourist #{tourist_name}")
22
+ tourists += 1
23
+ tourist = Tourist.make_tourist(tourist_name,@host,@tourists,@number,@runner_id)
24
+ tourist.before_tours
28
25
 
29
- tour.tests.each do |test|
26
+ tourist.tours.each do |tour|
30
27
  times = Hash.new {|h,k| h[k] = {}}
31
28
 
32
- next if test_limited_to(test) # test_list && !test_list.empty? && !test_list.include?(test.to_s)
29
+ next if tour_limited_to(tour)
33
30
 
34
31
  begin
35
- tests += 1
36
- times[test][:started] = Time.now
37
- tour.run_test test
32
+ tours += 1
33
+ times[tour][:started] = Time.now
34
+ tourist.run_tour tour
38
35
  passes += 1
39
36
  rescue TourBusException, WebratError => e
40
37
  log("********** FAILURE IN RUN! **********")
@@ -53,18 +50,18 @@ class Runner
53
50
  end
54
51
  errors += 1
55
52
  ensure
56
- times[test][:finished] = Time.now
57
- times[test][:elapsed] = times[test][:finished] - times[test][:started]
53
+ times[tour][:finished] = Time.now
54
+ times[tour][:elapsed] = times[tour][:finished] - times[tour][:started]
58
55
  end
59
- log("Finished run #{num}/#{number} of Tour #{tour_name}")
56
+ log("Finished run #{num}/#{number} of Tourist #{tourist_name}")
60
57
  end
61
58
 
62
- tour.after_tour
59
+ tourist.after_tours
63
60
  end
64
61
  log("Finished #{@runner_type} run #{num}/#{number}")
65
62
  end
66
- log("Finished all #{@runner_type} tours.")
67
- [tours,tests,passes,fails,errors]
63
+ log("Finished all #{@runner_type} tourists.")
64
+ [tourists,tours,passes,fails,errors]
68
65
  end
69
66
 
70
67
  protected
@@ -73,8 +70,8 @@ class Runner
73
70
  puts "#{Time.now.strftime('%F %H:%M:%S')} Runner ##{@runner_id}: #{message}"
74
71
  end
75
72
 
76
- def test_limited_to(test_name)
77
- @test_list && !@test_list.empty? && !@test_list.include?(test_name.to_s)
73
+ def tour_limited_to(tour_name)
74
+ @tour_list && !@tour_list.empty? && !@tour_list.include?(tour_name.to_s)
78
75
  end
79
76
  end
80
77
 
data/lib/tour_bus.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'benchmark'
2
2
 
3
3
  class TourBus < Monitor
4
- attr_reader :host, :concurrency, :number, :tours, :runs, :tests, :passes, :fails, :errors, :benchmarks
4
+ attr_reader :host, :concurrency, :number, :tourists, :runs, :tests, :passes, :fails, :errors, :benchmarks
5
5
 
6
- def initialize(host="localhost", concurrency=1, number=1, tours=[], test_list=nil)
7
- @host, @concurrency, @number, @tours, @test_list = host, concurrency, number, tours, test_list
6
+ def initialize(host="localhost", concurrency=1, number=1, tourists=[], test_list=nil)
7
+ @host, @concurrency, @number, @tourists, @test_list = host, concurrency, number, tourists, test_list
8
8
  @runner_id = 0
9
9
  @runs, @tests, @passes, @fails, @errors = 0,0,0,0,0
10
10
  super()
@@ -38,7 +38,7 @@ class TourBus < Monitor
38
38
  end
39
39
 
40
40
  def total_runs
41
- tours.size * concurrency * number
41
+ tourists.size * concurrency * number
42
42
  end
43
43
 
44
44
  def run
@@ -46,10 +46,10 @@ class TourBus < Monitor
46
46
  threads_ready = 0
47
47
  start_running = false
48
48
  mutex = Mutex.new
49
- tour_name = "#{total_runs} runs: #{concurrency}x#{number} of #{tours * ','}"
49
+ tourist_name = "#{total_runs} runs: #{concurrency}x#{number} of #{tourists * ','}"
50
50
  started = Time.now.to_f
51
51
  concurrency.times do |conc|
52
- log "Starting #{tour_name}"
52
+ log "Starting #{tourist_name}"
53
53
  threads << Thread.new do
54
54
  runner_id = next_runner_id
55
55
  mutex.lock
@@ -62,8 +62,8 @@ class TourBus < Monitor
62
62
  sleep 0.05 until start_running
63
63
  runs,tests,passes,fails,errors,start = 0,0,0,0,0,Time.now.to_f
64
64
  bm = Benchmark.measure do
65
- runner = Runner.new(@host, @tours, @number, runner_id, @test_list)
66
- runs,tests,passes,fails,errors = runner.run_tours
65
+ runner = Runner.new(@host, @tourists, @number, runner_id, @test_list)
66
+ runs,tests,passes,fails,errors = runner.run_tourists
67
67
  update_stats runs, tests, passes, fails, errors
68
68
  end
69
69
  log "Runner Finished!"
@@ -76,9 +76,9 @@ class TourBus < Monitor
76
76
  threads.each {|t| t.join }
77
77
  finished = Time.now.to_f
78
78
  log '-' * 80
79
- log tour_name
79
+ log tourist_name
80
80
  log "All Runners finished."
81
- log "Total Tours: #{@runs}"
81
+ log "Total Tourists: #{@runs}"
82
82
  log "Total Tests: #{@tests}"
83
83
  log "Total Passes: #{@passes}"
84
84
  log "Total Fails: #{@fails}"
data/lib/tour_proxy.rb ADDED
@@ -0,0 +1,82 @@
1
+ require 'webrick/httpproxy'
2
+ require 'ruby-debug'
3
+
4
+ class TourProxy
5
+ # Initialize the proxy object.
6
+ #
7
+ # @param [Hash] options list of options to configure the proxy.
8
+ # @option options [Fixnum] :port Port number to listen on
9
+ # @option options [Hash] :hostnames hostnames by name => url
10
+ # @option options [IO] :output_buffer IO object to write output to
11
+ def initialize(options={})
12
+ @server = nil
13
+ @output_buffer = options[:output_buffer] || STDOUT
14
+ @server = WEBrick::HTTPProxyServer.new(
15
+ :Port => options[:port] || 8080,
16
+ :RequestCallback => Proc.new do |req,res|
17
+ log_request_as_webrat(req)
18
+ # dump_request(req)
19
+ # puts(("<" * 100) + " END CALLBACK")
20
+ end
21
+ )
22
+ end
23
+
24
+ def log_request_as_webrat(request)
25
+ return unless @output_buffer
26
+ # puts "> log_request_as_webrat"
27
+ body = request.body
28
+ if body
29
+ items = body.split(/&/)
30
+ pairs = items.map{ |e| e.split(/=/,2)}
31
+ hash = Hash[pairs]
32
+ @output_buffer.puts "visit '#{request.request_uri}', :#{request.request_method.downcase}, #{hash.inspect}"
33
+ else
34
+ @output_buffer.puts "visit '#{request.request_uri}', :#{request.request_method.downcase}"
35
+ end
36
+ # puts "< log_request_as_webrat"
37
+ end
38
+
39
+ # Dumps an HTTPRequest object
40
+ def dump_request(request)
41
+ return unless @output_buffer
42
+ puts "> dump_request"
43
+ terms = %w(request_uri request_line raw_header body)
44
+ longest = terms.map(&:size).max
45
+
46
+ @output_buffer.puts '-' * 80
47
+ @output_buffer.puts "Request:"
48
+ terms.each do |term|
49
+ @output_buffer.puts " %#{longest}s:" % [term] # , request.send(term).to_s.length]
50
+ end
51
+ @output_buffer.puts '-' * 80
52
+ @output_buffer.flush
53
+ puts "< dump_request"
54
+ end
55
+
56
+ # Dumps an HTTPResponse object
57
+ def dump_response(response)
58
+ return unless @output_buffer
59
+ puts "> dump_response"
60
+ terms = %w()
61
+ longest = terms.map(&:size).max
62
+
63
+ @output_buffer.puts '-' * 80
64
+ @output_buffer.puts "Response:"
65
+ terms.each do |term|
66
+ @output_buffer.puts " %#{longest}s: %s" % [term, response.send(term).to_s]
67
+ end
68
+ @output_buffer.puts '-' * 80
69
+ @output_buffer.flush
70
+ puts "< dump_response"
71
+ end
72
+
73
+ def start
74
+ @server.start
75
+ end
76
+
77
+ def shutdown
78
+ @server.shutdown
79
+ end
80
+ end
81
+
82
+
data/lib/tour_rat.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'forwardable'
2
+ require 'webrat'
3
+
4
+ module TourRat
5
+ module ClassMethods
6
+
7
+ end
8
+
9
+ module InstanceMethods
10
+
11
+ end
12
+
13
+ def self.included(receiver)
14
+ receiver.extend ClassMethods
15
+ receiver.send :include, InstanceMethods
16
+ end
17
+ end
18
+
19
+ # Webrat::Scope
20
+ # 1. attach_file
21
+ # 2. check
22
+ # 3. choose
23
+ # 4. click_area
24
+ # 5. click_button
25
+ # 6. click_link
26
+ # 7. fill_in
27
+ # 8. select
28
+ # 9. select_date
29
+ # 10. select_datetime
30
+ # 11. select_time
31
+ # 12. set_hidden_field
32
+ # 13. submit_form
33
+ # 14. uncheck
34
+ #
35
+ #
36
+ # Webrat::Session
37
+ # 1. automate
38
+ # 2. basic_auth
39
+ # 3. check_for_infinite_redirects
40
+ # 4. click_link_within
41
+ # 5. dom
42
+ # 6. header
43
+ # 7. http_accept
44
+ # 8. infinite_redirect_limit_exceeded?
45
+ # 9. internal_redirect?
46
+ # 10. redirected_to
47
+ # 11. reload
48
+ # 12. simulate
49
+ # 13. visit
50
+ # 14. within
51
+ # 15. xml_content_type?
52
+ #
53
+ # Webrat::HaveTagMatcher
54
+ # 1. assert_have_no_tag
55
+ # 2. assert_have_tag
56
+ # 3. have_tag
57
+ # 4. match_tag
58
+ #
59
+ # Webrat::Matchers
60
+ # 1. assert_contain
61
+ # 2. assert_have_no_selector
62
+ # 3. assert_have_no_xpath
63
+ # 4. assert_have_selector
64
+ # 5. assert_have_xpath
65
+ # 6. assert_not_contain
66
+ # 7. contain
67
+ # 8. have_selector
68
+ # 9. have_xpath
69
+ # 10. match_selector
70
+ # 11. match_xpath
data/lib/tour_watch.rb CHANGED
@@ -29,10 +29,10 @@ class TourWatch
29
29
  @mac ? fields_mac(parts) : fields_linux(parts)
30
30
  end
31
31
 
32
- # Note: MacOSX is so awesome I just cacked. Top will report 0.0% cpu
33
- # the first time you run top, every time. The only way to get actual
34
- # CPU% here is to wait for it to send another page and then throw
35
- # away the first page. Isn't that just awesome?!? I KNOW!!!
32
+ # Note: MacOSX is so laaaame. Top will report 0.0% cpu the first
33
+ # time you run top, every time. The only way to get actual CPU% here
34
+ # is to wait for it to send another page and then throw away the
35
+ # first page. Isn't that just awesome?!? I KNOW!!!
36
36
  def top_mac
37
37
  top = `top -l 1 | grep -E '(#{@processes})'`
38
38
  end
data/lib/tourist.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'forwardable'
2
+ require 'monitor'
3
+ require 'common'
4
+ require 'webrat'
5
+ require 'webrat/adapters/mechanize'
6
+ require 'test/unit/assertions'
7
+
8
+ # A tourist is essentially a test suite file. A Tourist subclass
9
+ # encapsulates a set of tours that can be done, and may contain helper
10
+ # and support methods for a given task. If you have a two or three
11
+ # paths through a specific area of your website, define a tourist for
12
+ # that area and create tour_ methods for each type of tour to be done.
13
+
14
+ Webrat.configure do |config|
15
+ config.mode = :mechanize
16
+ end
17
+
18
+ class Tourist
19
+ extend Forwardable
20
+ include Webrat::Methods
21
+ include Webrat::Matchers
22
+ include Webrat::SaveAndOpenPage
23
+ include Test::Unit::Assertions
24
+
25
+ attr_reader :host, :tours, :number, :tour_type, :tourist_id
26
+
27
+ def initialize(host, tours, number, tourist_id)
28
+ @host, @tours, @number, @tourist_id = host, tours, number, tourist_id
29
+ @tour_type = self.send(:class).to_s
30
+ end
31
+
32
+ # before_tour runs once per tour, before any tours get run
33
+ def before_tours; end
34
+
35
+ # after_tour runs once per tour, after all the tours have run
36
+ def after_tours; end
37
+
38
+ def setup
39
+ end
40
+
41
+ def teardown
42
+ end
43
+
44
+ def wait(time)
45
+ sleep time.to_i
46
+ end
47
+
48
+ # Lists tourists in tours folder. If a string is given, filters the
49
+ # list by that string. If an array of filter strings is given,
50
+ # returns items that match ANY filter string in the array.
51
+ def self.tourists(filter=[])
52
+ filter = [filter].flatten
53
+ # All files in tours folder, stripped to basename, that match any item in filter
54
+ # I do loves me a long chain. This returns an array containing
55
+ # 1. All *.rb files in tour folder (recursive)
56
+ # 2. Each filename stripped to its basename
57
+ # 3. If you passed in any filters, these basenames are rejected unless they match at least one filter
58
+ # 4. The filenames remaining are then checked to see if they define a class of the same name that inherits from Tourist
59
+ Dir[File.join('.', 'tours', '**', '*.rb')].map {|fn| File.basename(fn, ".rb")}.select {|fn| filter.size.zero? || filter.any?{|f| fn =~ /#{f}/}}.select {|tour| Tourist.tourist? tour }
60
+ end
61
+
62
+ def self.tours(tourist_name)
63
+ Tourist.make_tourist(tourist_name).tours
64
+ end
65
+
66
+ # Returns true if the given tourist name can be found in the tours folder, and defines a similarly-named subclass of Tourist
67
+ def self.tourist?(tourist_name)
68
+ Object.const_defined?(tourist_name.classify) && tourist_name.classify.constantize.ancestors.include?(Tourist)
69
+ end
70
+
71
+ # Factory method, creates the named child class instance
72
+ def self.make_tourist(tourist_name,host="http://localhost:3000",tours=[],number=1,tourist_id=nil)
73
+ tourist_name.classify.constantize.new(host,tours,number,tourist_id)
74
+ end
75
+
76
+ # Returns list of tours this tourist knows about. (Meant to be run on a subclass
77
+ # instance; returns the list of tours available).
78
+ def tours
79
+ methods.grep(/^tour_/).map {|m| m.sub(/^tour_/,'')}
80
+ end
81
+
82
+ def run_tour(tour_name)
83
+ @current_tour = "tour_#{tour_name}"
84
+ raise TourBusException.new("run_tour couldn't run tour '#{tour_name}' because this tourist did not respond to :#{@current_tour}") unless respond_to? @current_tour
85
+ setup
86
+ send @current_tour
87
+ teardown
88
+ end
89
+
90
+ protected
91
+
92
+ def session
93
+ @session ||= Webrat::MechanizeSession.new
94
+ end
95
+
96
+ def log(message)
97
+ puts "#{Time.now.strftime('%F %H:%M:%S')} Tourist ##{@tourist_id}: (#{@current_tour}) #{message}"
98
+ end
99
+
100
+ end
101
+
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe TourProxy do
4
+ it "should replace known hostnames"
5
+ # given a list of known hostnames,
6
+ # when I process a request matching a hosts,
7
+ # then the request uri should be rewritten with the variable's expansion
8
+
9
+ it "should emit AMF blobs"
10
+ it "should emit get/post blobs for unrecognized types"
11
+
12
+ # when doing an html get
13
+ # with no params
14
+ # it should log "visit 'url'"
15
+ # and should not log "visit 'url', :get" etc
16
+
17
+
18
+ end
19
+
@@ -0,0 +1,22 @@
1
+ # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
+ # from the project root directory.
3
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/file'))
4
+ require 'spec/autorun'
5
+ require 'ruby-debug'
6
+ # require File.here('../features/factories/fixjour_definitions')
7
+ # require File.here('../test/bdrb_test_helper')
8
+
9
+ # Requires all files in a folder relative to .. (project root).
10
+ def require_all_files_in_folder(folder, extension = '*.rb')
11
+ for file in Dir[File.join(File.expand_path(File.dirname(__FILE__)), '..', folder, "**/#{extension}")]
12
+ require file
13
+ end
14
+ end
15
+
16
+ # Uncomment the next line to use webrat's matchers
17
+ #require 'webrat/integrations/rspec-rails'
18
+
19
+ # Requires supporting files with custom matchers and macros, etc,
20
+ # in ./support/ and its subdirectories.
21
+ require_all_files_in_folder "spec/support"
22
+ require_all_files_in_folder "lib"
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tourbus
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 5
9
- version: 0.1.5
4
+ prerelease:
5
+ version: 2.0.1
10
6
  platform: ruby
11
7
  authors:
12
8
  - David Brady
@@ -18,20 +14,17 @@ autorequire:
18
14
  bindir: bin
19
15
  cert_chain: []
20
16
 
21
- date: 2010-03-29 00:00:00 -06:00
17
+ date: 2010-09-23 00:00:00 -06:00
22
18
  default_executable:
23
19
  dependencies:
24
20
  - !ruby/object:Gem::Dependency
25
21
  name: mechanize
26
22
  prerelease: false
27
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
28
25
  requirements:
29
26
  - - ">="
30
27
  - !ruby/object:Gem::Version
31
- segments:
32
- - 1
33
- - 0
34
- - 0
35
28
  version: 1.0.0
36
29
  type: :runtime
37
30
  version_requirements: *id001
@@ -39,11 +32,10 @@ dependencies:
39
32
  name: trollop
40
33
  prerelease: false
41
34
  requirement: &id002 !ruby/object:Gem::Requirement
35
+ none: false
42
36
  requirements:
43
37
  - - ">="
44
38
  - !ruby/object:Gem::Version
45
- segments:
46
- - 0
47
39
  version: "0"
48
40
  type: :runtime
49
41
  version_requirements: *id002
@@ -51,11 +43,10 @@ dependencies:
51
43
  name: faker
52
44
  prerelease: false
53
45
  requirement: &id003 !ruby/object:Gem::Requirement
46
+ none: false
54
47
  requirements:
55
48
  - - ">="
56
49
  - !ruby/object:Gem::Version
57
- segments:
58
- - 0
59
50
  version: "0"
60
51
  type: :runtime
61
52
  version_requirements: *id003
@@ -63,11 +54,10 @@ dependencies:
63
54
  name: hpricot
64
55
  prerelease: false
65
56
  requirement: &id004 !ruby/object:Gem::Requirement
57
+ none: false
66
58
  requirements:
67
59
  - - ">="
68
60
  - !ruby/object:Gem::Version
69
- segments:
70
- - 0
71
61
  version: "0"
72
62
  type: :runtime
73
63
  version_requirements: *id004
@@ -75,21 +65,30 @@ dependencies:
75
65
  name: webrat
76
66
  prerelease: false
77
67
  requirement: &id005 !ruby/object:Gem::Requirement
68
+ none: false
78
69
  requirements:
79
70
  - - ">="
80
71
  - !ruby/object:Gem::Version
81
- segments:
82
- - 0
83
- - 7
84
- - 0
85
72
  version: 0.7.0
86
73
  type: :runtime
87
74
  version_requirements: *id005
88
- description: TourBus, a web stress-testing tool that combines complex 'tour' definitions with scalable concurrent testing
75
+ - !ruby/object:Gem::Dependency
76
+ name: activesupport
77
+ prerelease: false
78
+ requirement: &id006 !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 3.0.0
84
+ type: :runtime
85
+ version_requirements: *id006
86
+ description: TourBus, a web load-testing tool that combines complex 'tour' definitions with scalable, concurrent testing
89
87
  email: github@shinybit.com
90
88
  executables:
91
89
  - tourbus
92
90
  - tourwatch
91
+ - tourproxy
93
92
  extensions: []
94
93
 
95
94
  extra_rdoc_files:
@@ -98,16 +97,22 @@ extra_rdoc_files:
98
97
  - examples/contact_app/README.rdoc
99
98
  files:
100
99
  - bin/tourbus
100
+ - bin/tourproxy
101
101
  - bin/tourwatch
102
102
  - examples/contact_app/README.rdoc
103
103
  - examples/contact_app/contact_app.rb
104
104
  - examples/contact_app/tours/simple.rb
105
105
  - examples/contact_app/tours/tourbus.yml
106
106
  - lib/common.rb
107
+ - lib/file.rb
107
108
  - lib/runner.rb
108
- - lib/tour.rb
109
109
  - lib/tour_bus.rb
110
+ - lib/tour_proxy.rb
111
+ - lib/tour_rat.rb
110
112
  - lib/tour_watch.rb
113
+ - lib/tourist.rb
114
+ - spec/lib/tourproxy_spec.rb
115
+ - spec/spec_helper.rb
111
116
  - README.rdoc
112
117
  - MIT-LICENSE
113
118
  has_rdoc: true
@@ -121,27 +126,25 @@ rdoc_options:
121
126
  - --main
122
127
  - README.rdoc
123
128
  - --title
124
- - Tourbus - Web Stress Testing in Ruby
129
+ - Tourbus - Web Load Testing in Ruby
125
130
  require_paths:
126
131
  - lib
127
132
  required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
128
134
  requirements:
129
135
  - - ">="
130
136
  - !ruby/object:Gem::Version
131
- segments:
132
- - 0
133
137
  version: "0"
134
138
  required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
135
140
  requirements:
136
141
  - - ">="
137
142
  - !ruby/object:Gem::Version
138
- segments:
139
- - 0
140
143
  version: "0"
141
144
  requirements: []
142
145
 
143
146
  rubyforge_project:
144
- rubygems_version: 1.3.6
147
+ rubygems_version: 1.6.2
145
148
  signing_key:
146
149
  specification_version: 3
147
150
  summary: TourBus web stress-testing tool
data/lib/tour.rb DELETED
@@ -1,100 +0,0 @@
1
- require 'forwardable'
2
- require 'monitor'
3
- require 'common'
4
- require 'webrat'
5
- require 'webrat/adapters/mechanize'
6
- require 'test/unit/assertions'
7
-
8
- # A tour is essentially a test suite file. A Tour subclass
9
- # encapsulates a set of tests that can be done, and may contain helper
10
- # and support methods for a given task. If you have a two or three
11
- # paths through a specific area of your website, define a tour for
12
- # that area and create test_ methods for each type of test to be done.
13
-
14
- Webrat.configure do |config|
15
- config.mode = :mechanize
16
- end
17
-
18
- class Tour
19
- extend Forwardable
20
- include Webrat::Methods
21
- include Webrat::Matchers
22
- include Webrat::SaveAndOpenPage
23
- include Test::Unit::Assertions
24
-
25
- attr_reader :host, :tours, :number, :tour_type, :tour_id
26
-
27
- def initialize(host, tours, number, tour_id)
28
- @host, @tours, @number, @tour_id = host, tours, number, tour_id
29
- @tour_type = self.send(:class).to_s
30
- end
31
-
32
- # before_tour runs once per tour, before any tests get run
33
- def before_tour; end
34
-
35
- # after_tour runs once per tour, after all the tests have run
36
- def after_tour; end
37
-
38
- def setup
39
- end
40
-
41
- def teardown
42
- end
43
-
44
- def wait(time)
45
- sleep time.to_i
46
- end
47
-
48
- # Lists tours in tours folder. If a string is given, filters the
49
- # list by that string. If an array of filter strings is given,
50
- # returns items that match ANY filter string in the array.
51
- def self.tours(filter=[])
52
- filter = [filter].flatten
53
- # All files in tours folder, stripped to basename, that match any item in filter
54
- # I do loves me a long chain. This returns an array containing
55
- # 1. All *.rb files in tour folder (recursive)
56
- # 2. Each filename stripped to its basename
57
- # 3. If you passed in any filters, these basenames are rejected unless they match at least one filter
58
- # 4. The filenames remaining are then checked to see if they define a class of the same name that inherits from Tour
59
- Dir[File.join('.', 'tours', '**', '*.rb')].map {|fn| File.basename(fn, ".rb")}.select {|fn| filter.size.zero? || filter.any?{|f| fn =~ /#{f}/}}.select {|tour| Tour.tour? tour }
60
- end
61
-
62
- def self.tests(tour_name)
63
- Tour.make_tour(tour_name).tests
64
- end
65
-
66
- def self.tour?(tour_name)
67
- Object.const_defined?(tour_name.classify) && tour_name.classify.constantize.ancestors.include?(Tour)
68
- end
69
-
70
- # Factory method, creates the named child class instance
71
- def self.make_tour(tour_name,host="http://localhost:3000",tours=[],number=1,tour_id=nil)
72
- tour_name.classify.constantize.new(host,tours,number,tour_id)
73
- end
74
-
75
- # Returns list of tests in this tour. (Meant to be run on a subclass
76
- # instance; returns the list of tests available).
77
- def tests
78
- methods.grep(/^test_/).map {|m| m.sub(/^test_/,'')}
79
- end
80
-
81
- def run_test(test_name)
82
- @test = "test_#{test_name}"
83
- raise TourBusException.new("run_test couldn't run test '#{test_name}' because this tour did not respond to :#{@test}") unless respond_to? @test
84
- setup
85
- send @test
86
- teardown
87
- end
88
-
89
- protected
90
-
91
- def session
92
- @session ||= Webrat::MechanizeSession.new
93
- end
94
-
95
- def log(message)
96
- puts "#{Time.now.strftime('%F %H:%M:%S')} Tour ##{@tour_id}: (#{@test}) #{message}"
97
- end
98
-
99
- end
100
-