dbrady-tourbus 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,6 +6,7 @@ Flexible and scalable website testing tool.
6
6
 
7
7
  * David Brady -- david.brady@leadmediapartners.com
8
8
  * Tim Harper -- tim.harper@leadmediapartners.com
9
+ * James Britt -- http://github.com/jamesbritt
9
10
 
10
11
  == General Info
11
12
 
@@ -54,22 +55,48 @@ better name, these are called Tours.
54
55
 
55
56
  === Example TourBus Run
56
57
 
57
- tourbus -c 2 -n 3 simple
58
+ You want to invoke +tourbus+ from the parent directory of the @tours/@ folder.
58
59
 
59
- This will create 2 concurrent Tour runners, each of which will run all
60
+ For example, if you have this project tree ...
61
+
62
+ `-- contact_app
63
+ |-- README.rdoc
64
+ |-- contact_app.rb
65
+ `-- tours
66
+ |-- simple.rb
67
+ `-- tourbus.yml
68
+
69
+ ... then you execute +tourbus+ from the +contact_app/+ directory.
70
+
71
+ tourbus -c 2 -n 3 simple
72
+
73
+ That will run the +simple.rb+ tour file.
74
+
75
+ It will create 2 concurrent Tour runners, each of which will run all
60
76
  of the methods in Simple three times.
61
77
 
62
78
  * You can specify multiple tours.
63
79
 
80
+ tourbus -c 2 -n 3 simple1 simple2 simple3
81
+
64
82
  * If you don't specify a tour, all tours in ./tours will be run.
65
83
 
66
84
  * tourbus --help will give you more information.
67
85
 
86
+ * You can run tours and filter given tests.
87
+
88
+ tourbus -c 2 -n 3 simple -t test_login,test_logout
89
+
90
+ Note that if you specify multiple tours and filter tests, the filtered
91
+ tests will be run on all tours specified. If you do not specify a
92
+ tour, the filtered tests will be run on all tours found in the
93
+ +./tours+ folder.
94
+
68
95
  === Example TourWatch Run
69
96
 
70
97
  On the webserver, you can type
71
98
 
72
- tourwatch -c 4
99
+ tourwatch -c 4
73
100
 
74
101
  To begin running tourwatch. It's basically a stripped-down version of
75
102
  top with cheesy text graphs. (TourWatch's development cycles were
@@ -82,7 +109,7 @@ included in the 2 days for TourBus.)
82
109
 
83
110
  * You can choose which processes to watch by passing a csv to -p:
84
111
 
85
- tourwatch -p ruby,mongrel
112
+ tourwatch -p ruby,mongrel
86
113
 
87
114
  Each process name is a partial regexp, so the above would match
88
115
  mongrel AND mongrel_rails, etc.
@@ -110,7 +137,8 @@ duplications, oversights, and kludges.
110
137
  didn't put tests on it. I haven't put tests on it yet because I'm
111
138
  not sure how to go about it. Instead of exercising a web app with a
112
139
  test browser, we need to exercise a test browser with... um... a web
113
- app?
140
+ app? (dbrady notes: Now that we have a contact_app, we could try
141
+ writing some specs and features to run tourbus against it.)
114
142
 
115
143
  * Web-Sickle is another internal app, written by Tim Harper, that
116
144
  works "well enough". Until I open-sourced this project, it was a
@@ -118,12 +146,31 @@ duplications, oversights, and kludges.
118
146
  from WebSickle itself, so there's a lot of code in Runner that
119
147
  really belongs in WebSickle.
120
148
 
121
- * Documentation is horrible.
149
+ * Documentation is <strike>horrible</strike> merely quite bad.
122
150
 
123
151
  * There's not much in the way of examples, either. When I removed all
124
152
  the LMP-specific code, all of the examples went with it. Sorry about
125
153
  that. Coming soon.
126
154
 
155
+ == Feature Requests (How You Can Help!)
156
+
157
+ * I'd like to beef up the example contact app to show more of TourBus
158
+ than the simplest possible path. Adding in another page or two, and
159
+ then adding an additional tour or two would make it more apparent to
160
+ new users that you can do things like run multiple tours at once.
161
+ Also, having more than one test_ method in simple.rb would let us
162
+ demonstrate test filtering as well. (Be aware that at present
163
+ [2009-04-17], webrat still does not play well with Sinatra sessions
164
+ so there would be complications. dbrady's fork of webrat combines
165
+ jferris' fix with the latest webrat, and will be maintained until
166
+ main webrat includes the feature. That fork is at
167
+ http://github.com/dbrady/webrat)
168
+
169
+ * I'd like to remove WebSickle and replace it with Webrat. There is a
170
+ webrat branch on the main fork (http://github.com/dbrady/tourbus)
171
+ that is 90% complete. Once that's done we can start massaging the
172
+ API to be a little more friendly.
173
+
127
174
  == Credits
128
175
 
129
176
  * Tim Harper camped at my place for a day fixing bugs in WebSickle as
@@ -133,6 +180,9 @@ duplications, oversights, and kludges.
133
180
  source it. How much do they rock? All the way to 11, that's how much
134
181
  they rock.
135
182
 
183
+ * James Britt jumped on this and revived it as it was gathering dust.
184
+ Thanks!
185
+
136
186
  == License
137
187
 
138
188
  MIT. See the license file.
data/bin/tourbus CHANGED
@@ -7,7 +7,7 @@ require_all_files_in_folder 'tours'
7
7
  config_file = ["./tourbus.yml", "./tours/tourbus.yml", "./config/tourbus.yml", "~/tourbus.yml"].map {|p| File.expand_path(p)}.find {|p| File.exists? p}
8
8
  config = config_file ? YAML::load_file(config_file).symbolize_keys : {}
9
9
 
10
- config_map = { :host => :to_s, :concurrency => :to_i, :number => :to_i, :rand => :to_i }
10
+ config_map = { :host => :to_s, :concurrency => :to_i, :number => :to_i, :rand => :to_i, :tests => :to_s }
11
11
  config_map.each {|key,conv| config[key] = config[key].send(conv) if config.key? key }
12
12
 
13
13
  # defaults
@@ -22,10 +22,11 @@ opts = Trollop.options do
22
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
23
  opt :list, "List tours and runs available. If tours or runs are included, filters the list", :type => :boolean, :default => nil
24
24
  opt :rand, "Random seed", :type => :integer, :default => config[:rand]
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
25
26
  end
26
27
 
27
28
  tours = if ARGV.empty?
28
- Dir[File.join('.', 'tours', '*.rb')].map {|f| File.basename(f, ".rb")}
29
+ Tour.tours
29
30
  else
30
31
  ARGV
31
32
  end
@@ -38,6 +39,8 @@ if opts[:list]
38
39
  puts Tour.tests(tour).map {|test| " #{test}"}
39
40
  end
40
41
  else
41
- TourBus.new(opts[:host], opts[:concurrency], opts[:number], tours).run
42
+ opts[:tests] = opts[:tests].split(',')
43
+
44
+ TourBus.new(opts[:host], opts[:concurrency], opts[:number], tours, opts[:tests]).run
42
45
  end
43
46
 
data/lib/runner.rb CHANGED
@@ -4,23 +4,31 @@ require 'common'
4
4
  class Runner
5
5
  attr_reader :host, :tours, :number, :runner_type, :runner_id
6
6
 
7
- def initialize(host, tours, number, runner_id)
8
- @host, @tours, @number, @runner_id = host, tours, number, runner_id
7
+ def initialize(host, tours, number, runner_id, test_list)
8
+ @host, @tours, @number, @runner_id, @test_list = host, tours, number, runner_id, test_list
9
9
  @runner_type = self.send(:class).to_s
10
10
  log("Ready to run #{@runner_type}")
11
11
  end
12
12
 
13
13
  # Dispatches to subclass run method
14
- def run_tours
15
- runs,passes,fails,errors = 0,0,0,0
14
+ def run_tours test_list = []
15
+ log "Filtering on tests #{test_list.join(', ')}" unless test_list.to_a.empty?
16
+ tours,tests,passes,fails,errors = 0,0,0,0,0
16
17
  1.upto(number) do |num|
17
18
  log("Starting #{@runner_type} run #{num}/#{number}")
18
- @tours.each do |tour|
19
- runs += 1
20
- tour = Tour.make_tour(tour,@host,@tours,@number,@runner_id)
19
+ @tours.each do |tour_name|
20
+
21
+ log("Starting run #{number} of Tour #{tour_name}")
22
+ tours += 1
23
+ tour = Tour.make_tour(tour_name,@host,@tours,@number,@runner_id)
21
24
  tour.tests.each do |test|
25
+
26
+ next if !test_list.empty? && !test_list.include?(test.to_s)
27
+
22
28
  begin
29
+ tests += 1
23
30
  tour.run_test test
31
+ passes += 1
24
32
  rescue TourBusException, WebsickleException => e
25
33
  log("********** FAILURE IN RUN! **********")
26
34
  log e.message
@@ -38,14 +46,13 @@ class Runner
38
46
  end
39
47
  errors += 1
40
48
  end
41
-
49
+ log("Finished run #{number} of Tour #{tour_name}")
42
50
  end
43
51
  end
44
- passes += 1
45
52
  log("Finished #{@runner_type} run #{num}/#{number}")
46
53
  end
47
- log("Finished all #{@runner_type} runs.")
48
- [runs,passes,fails,errors]
54
+ log("Finished all #{@runner_type} tours.")
55
+ [tours,tests,passes,fails,errors]
49
56
  end
50
57
 
51
58
  protected
data/lib/tour.rb CHANGED
@@ -117,5 +117,22 @@ class Tour
117
117
  end
118
118
  log "Page body ok (matches #{pattern})"
119
119
  end
120
+
121
+
122
+
123
+ # True if page does not contain (or match) the given string (or regexp)
124
+ #
125
+ # TODO: Refactor me--these were separated out back when Websickle
126
+ # was a shared submodule and we couldn't pollute it. Now that it's
127
+ # frozen these probably belong there.
128
+ def assert_page_body_does_not_contain(pattern)
129
+ case pattern
130
+ when String:
131
+ raise WebsickleException, "Expected page body to not contain String '#{pattern}' but it did. It was #{page.body}" if page.body.to_s.index(pattern)
132
+ when Regexp:
133
+ raise WebsickleException, "Expected page body to not match Regexp '#{pattern}' but it did. It was #{page.body}" if page.body.to_s =~ pattern
134
+ end
135
+ log "Page body ok (does not match #{pattern})"
136
+ end
120
137
  end
121
138
 
data/lib/tour_bus.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'benchmark'
2
2
 
3
3
  class TourBus < Monitor
4
- attr_reader :host, :concurrency, :number, :tours, :runs, :passes, :fails, :errors, :benchmarks
4
+ attr_reader :host, :concurrency, :number, :tours, :runs, :tests, :passes, :fails, :errors, :benchmarks
5
5
 
6
- def initialize(host="localhost", concurrency=1, number=1, tours=[])
7
- @host, @concurrency, @number, @tours = host, concurrency, number, tours
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
8
8
  @runner_id = 0
9
- @runs, @passes, @fails, @errors = 0,0,0,0
9
+ @runs, @tests, @passes, @fails, @errors = 0,0,0,0,0
10
10
  super()
11
11
  end
12
12
 
@@ -16,9 +16,10 @@ class TourBus < Monitor
16
16
  end
17
17
  end
18
18
 
19
- def update_stats(runs,passes,fails,errors)
19
+ def update_stats(runs,tests,passes,fails,errors)
20
20
  synchronize do
21
21
  @runs += runs
22
+ @tests += tests
22
23
  @passes += passes
23
24
  @fails += fails
24
25
  @errors += errors
@@ -48,11 +49,11 @@ class TourBus < Monitor
48
49
  log "Starting #{tour_name}"
49
50
  threads << Thread.new do
50
51
  runner_id = next_runner_id
51
- runs,passes,fails,errors,start = 0,0,0,0,Time.now.to_f
52
+ runs,tests,passes,fails,errors,start = 0,0,0,0,0,Time.now.to_f
52
53
  bm = Benchmark.measure do
53
- runner = Runner.new(@host, @tours, @number, runner_id)
54
- runs,passes,fails,errors = runner.run_tours
55
- update_stats runs, passes, fails, errors
54
+ runner = Runner.new(@host, @tours, @number, runner_id, @test_list)
55
+ runs,tests,passes,fails,errors = runner.run_tours(@test_list)
56
+ update_stats runs, tests, passes, fails, errors
56
57
  end
57
58
  log "Runner Finished!"
58
59
  log "Runner finished in %0.3f seconds" % (Time.now.to_f - start)
@@ -66,12 +67,13 @@ class TourBus < Monitor
66
67
  log '-' * 80
67
68
  log tour_name
68
69
  log "All Runners finished."
69
- log "Total Runs: #{@runs}"
70
+ log "Total Tours: #{@runs}"
71
+ log "Total Tests: #{@tests}"
70
72
  log "Total Passes: #{@passes}"
71
73
  log "Total Fails: #{@fails}"
72
74
  log "Total Errors: #{@errors}"
73
75
  log "Elapsed Time: #{finished - started}"
74
- log "Speed: %5.3f v/s" % (@runs / (finished-started))
76
+ log "Speed: %5.3f tours/sec" % (@runs / (finished-started))
75
77
  log '-' * 80
76
78
  if @fails > 0 || @errors > 0
77
79
  log '********************************************************************************'
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbrady-tourbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Brady
8
+ - James Britt
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-01-10 00:00:00 -08:00
13
+ date: 2009-04-17 00:00:00 -07:00
13
14
  default_executable:
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
@@ -52,7 +53,7 @@ dependencies:
52
53
  - !ruby/object:Gem::Version
53
54
  version: "0"
54
55
  version:
55
- description: TourBus web stress-testing tool
56
+ description: TourBus, a web stress-testing tool that combines complex 'tour' definitions with scalable concurrent testing
56
57
  email: github@shinybit.com
57
58
  executables:
58
59
  - tourbus
@@ -60,7 +61,7 @@ executables:
60
61
  extensions: []
61
62
 
62
63
  extra_rdoc_files:
63
- - README.txt
64
+ - README.rdoc
64
65
  - MIT-LICENSE
65
66
  - examples/contact_app/README.rdoc
66
67
  files:
@@ -86,16 +87,16 @@ files:
86
87
  - lib/web-sickle/spec/spec_helper.rb
87
88
  - lib/web-sickle/spec/spec_helpers/mechanize_mock_helper.rb
88
89
  - lib/web-sickle/spec/web_sickle_spec.rb
89
- - README.txt
90
+ - README.rdoc
90
91
  - MIT-LICENSE
91
92
  has_rdoc: true
92
- homepage: http://github.com/dbrady/tourbus
93
+ homepage: http://github.com/jamesbritt/tourbus/
93
94
  post_install_message:
94
95
  rdoc_options:
95
96
  - --line-numbers
96
97
  - --inline-source
97
98
  - --main
98
- - README.txt
99
+ - README.rdoc
99
100
  - --title
100
101
  - Tourbus - Web Stress Testing in Ruby
101
102
  require_paths: