solutious-stella 0.7.0.004 → 0.7.0.005

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/bin/stella +16 -20
  2. data/examples/essentials/logo.png +0 -0
  3. data/examples/{basic → essentials}/plan.rb +7 -3
  4. data/examples/{basic → essentials}/search_terms.csv +0 -0
  5. data/examples/example_webapp.rb +7 -4
  6. data/examples/example_webapp.ru +3 -0
  7. data/lib/stella.rb +18 -26
  8. data/lib/stella/cli.rb +4 -1
  9. data/lib/stella/client.rb +49 -26
  10. data/lib/stella/data.rb +35 -9
  11. data/lib/stella/data/http.rb +1 -1
  12. data/lib/stella/data/http/request.rb +3 -14
  13. data/lib/stella/engine.rb +10 -4
  14. data/lib/stella/engine/functional.rb +2 -4
  15. data/lib/stella/engine/load.rb +24 -21
  16. data/lib/stella/mixins.rb +1 -1
  17. data/lib/stella/stats.rb +17 -4
  18. data/lib/stella/testplan/usecase.rb +2 -2
  19. data/lib/stella/utils.rb +16 -1
  20. data/lib/stella/version.rb +1 -1
  21. data/stella.gemspec +17 -4
  22. data/vendor/httpclient-2.1.5.2/httpclient.rb +1025 -0
  23. data/vendor/httpclient-2.1.5.2/httpclient/auth.rb +522 -0
  24. data/vendor/httpclient-2.1.5.2/httpclient/cacert.p7s +1579 -0
  25. data/vendor/httpclient-2.1.5.2/httpclient/cacert_sha1.p7s +1579 -0
  26. data/vendor/httpclient-2.1.5.2/httpclient/connection.rb +84 -0
  27. data/vendor/httpclient-2.1.5.2/httpclient/cookie.rb +562 -0
  28. data/vendor/httpclient-2.1.5.2/httpclient/http.rb +867 -0
  29. data/vendor/httpclient-2.1.5.2/httpclient/session.rb +864 -0
  30. data/vendor/httpclient-2.1.5.2/httpclient/ssl_config.rb +417 -0
  31. data/vendor/httpclient-2.1.5.2/httpclient/stats.rb +90 -0
  32. data/vendor/httpclient-2.1.5.2/httpclient/timeout.rb +136 -0
  33. data/vendor/httpclient-2.1.5.2/httpclient/util.rb +86 -0
  34. metadata +17 -4
  35. data/lib/stella/dsl.rb +0 -5
data/bin/stella CHANGED
@@ -18,9 +18,9 @@
18
18
  #
19
19
  #--
20
20
 
21
- STELLA_LIB_HOME = File.expand_path File.join(File.dirname(__FILE__), '..', 'lib')
22
-
23
- $:.unshift STELLA_LIB_HOME # Put our local lib in first place
21
+ # Put our local lib in first place
22
+ lib_dir = File.expand_path File.join(File.dirname(__FILE__), '..', 'lib')
23
+ $:.unshift lib_dir
24
24
 
25
25
  require 'drydock'
26
26
  require 'stella'
@@ -31,7 +31,6 @@ class Stella::CLI::Definition
31
31
  extend Drydock
32
32
 
33
33
  debug :off
34
- default :verify # when no command is provided
35
34
 
36
35
  # ---------------------------------------- STELLA GLOBALS --------
37
36
  # ------------------------------------------------------------------
@@ -56,32 +55,28 @@ class Stella::CLI::Definition
56
55
 
57
56
  # ------------------------------------------------ STELLA --------
58
57
  # ------------------------------------------------------------------
59
-
58
+
60
59
  about "Run a functional test"
61
60
  usage "stella verify http://stellaaahhhh.com/"
62
61
  usage "stella verify -p path/2/testplan.rb http://stellaaahhhh.com/"
63
62
  option :b, :benchmark, "Benchmark mode (ignore wait times)"
64
- option :p, :testplan, String, "Path to testplan" do |v|
65
- raise Stella::InvalidOption, "Bad path: #{v}" unless File.exists?(v)
66
- v
67
- end
63
+ option :p, :testplan, String, "Path to testplan"
68
64
  command :verify => Stella::CLI
69
65
 
70
66
  about "Run a load test"
71
67
  usage "stella load http://stellaaahhhh.com/"
72
- usage "stella load -p path/2/testplan.rb http://stellaaahhhh.com/"
68
+ usage "stella load http://stellaaahhhh.com:3114/"
69
+ usage "stella load --clients=10 --repetitions=2 http://stellaaahhhh.com/"
70
+ usage "stella load -p path/2/testplan.rb -u 100 -r 5 http://stellaaahhhh.com/"
73
71
  option :b, :benchmark, "Benchmark mode (ignore wait times)"
74
- option :u, :users, Integer, "Number of virtual users"
75
- option :r, :repetitions, Integer, "Number of times to repeat the testplan (per vuser)"
72
+ option :c, :clients, Integer, "Number of virtual clients"
73
+ option :r, :repetitions, Integer, "Number of times to repeat the testplan (per vclient)"
76
74
  option :t, :time, String, "Max duration to run test"
77
- option :d, :delay, Float, "Delay between client requests (s)"
78
- option :p, :testplan, String, "Path to testplan" do |v|
79
- raise Stella::InvalidOption, "Bad path: #{v}" unless File.exists?(v)
80
- v
81
- end
75
+ option :d, :delay, Float, "Delay (in seconds) between client requests (ignored if testplan supplied)"
76
+ option :p, :testplan, String, "Path to testplan"
82
77
  command :load => Stella::CLI
83
78
 
84
- about "Initialize Stella"
79
+ about "Initialize Stella configuration"
85
80
  command :init do
86
81
  Stella::Config.init
87
82
  end
@@ -103,13 +98,14 @@ class Stella::CLI::Definition
103
98
  end
104
99
 
105
100
  after do |obj|
106
- Drydock::Screen.flush
101
+ Stella.lflush
107
102
  @elapsed = Time.now - @start
108
103
  if Stella.loglev > 1 && @elapsed > 0.1
109
104
  puts
110
105
  puts "Elapsed: %.2f seconds" % @elapsed.to_f
111
106
  end
112
- exit obj.exit_code || 0
107
+ code = obj.exit_code if obj.respond_to? :exit_code
108
+ exit code ||= 0
113
109
  end
114
110
 
115
111
  end
File without changes
@@ -2,7 +2,7 @@
2
2
 
3
3
  desc "Business Finder Testplan"
4
4
 
5
- usecase 65, "Simple search" do
5
+ xusecase 65, "Simple search" do
6
6
  resource :search_terms, list('search_terms.csv')
7
7
 
8
8
  get "/", "Homepage" do
@@ -23,6 +23,9 @@ usecase 65, "Simple search" do
23
23
  listing = doc.css('div.listing').first
24
24
  set :lid, listing['id'].match(/(\d+)/)[0]
25
25
  end
26
+ response 404 do
27
+ quit "No results"
28
+ end
26
29
  end
27
30
 
28
31
  get "/listing/:lid" do # URIs can contain variables.
@@ -36,14 +39,15 @@ usecase 10, "Self-serve" do
36
39
  post "/listing/add", "Add a listing" do
37
40
  wait 1..4
38
41
  param :name => random(8)
39
- param :city => "Vancouver"
42
+ param :city => sequential("Montreal", "Toronto", "Vancouver")
43
+ param :logo => file('logo.png')
40
44
  response 302 do
41
45
  repeat 3
42
46
  end
43
47
  end
44
48
  end
45
49
 
46
- usecase "Listing API" do
50
+ xusecase "Listing API" do
47
51
 
48
52
  get '/listings.yaml', "View All" do
49
53
  response 200 do
@@ -1,14 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- # Use Ruby 1.8
4
-
5
3
  require "rubygems"
6
- require "rack"
7
4
  require "sinatra"
8
5
 
9
6
  require 'yaml'
10
7
 
11
- set :run => true
8
+ set :run => $0 == __FILE__ ? true : false
12
9
  set :environment => :development
13
10
  set :dump_errors => true
14
11
  set :port => 3114
@@ -78,6 +75,12 @@ post '/listing/add' do
78
75
  if find_name(params[:name], @listings).empty?
79
76
  @listings.shift if @listings.size >= options.max_listings
80
77
  @listings << { :name => params[:name], :id => rand(100000), :city => params[:city] }
78
+ if params[:logo].is_a?(Hash) && params[:logo][:tempfile]
79
+ p "TODO: Fix uploads"
80
+ #p params[:logo]
81
+ #FileUtils.mv params[:logo][:tempfile].path, "logo-#{params[:name]}"
82
+ end
83
+
81
84
  redirect '/listings'
82
85
  else
83
86
  status 500
@@ -0,0 +1,3 @@
1
+ dir = ::File.expand_path(::File.dirname(__FILE__))
2
+ require ::File.join(dir, 'example_webapp.rb')
3
+ run Sinatra::Application
@@ -1,43 +1,28 @@
1
1
 
2
- unless defined?(STELLA_LIB_HOME)
3
- STELLA_LIB_HOME = File.expand_path File.dirname(__FILE__)
4
- end
5
-
6
- local_libs = %w{drydock storable sysinfo gibbler}
7
- local_libs.each { |dir| $:.unshift File.join(STELLA_LIB_HOME, '..', '..', dir, 'lib') }
8
- #require 'rubygems'
9
-
10
- require 'storable'
11
- require 'sysinfo'
12
- require 'gibbler'
13
- require 'gibbler/aliases'
14
2
  require 'ostruct'
15
3
  require 'threadify'
16
- require 'drydock/screen'
17
4
 
18
5
  module Stella
19
6
  extend self
20
- require 'stella/version'
21
- require 'stella/exceptions'
22
- require 'stella/utils'
23
- require 'stella/stats'
24
- require 'stella/mixins'
25
- require 'stella/dsl'
26
- require 'stella/engine'
27
- require 'stella/testplan'
28
7
 
29
- autoload :Utils, STELLA_LIB_HOME + "/stella/utils"
30
- autoload :Data, STELLA_LIB_HOME + "/stella/data"
31
- autoload :Config, STELLA_LIB_HOME + "/stella/config"
32
- autoload :Client, STELLA_LIB_HOME + "/stella/client"
8
+ LIB_HOME = File.expand_path File.dirname(__FILE__) unless defined?(LIB_HOME)
9
+
10
+ %w{storable sysinfo gibbler}.each do |dir|
11
+ $:.unshift File.join(LIB_HOME, '..', '..', dir, 'lib')
12
+ end
13
+ require 'storable'
14
+ require 'sysinfo'
15
+ require 'gibbler'
16
+ require 'gibbler/aliases'
17
+ require 'drydock/screen'
33
18
 
34
19
  @@sysinfo = SysInfo.new.freeze
35
-
36
20
  @@logger = Drydock::Screen
37
21
  @@loglev = 1
38
22
  @@debug = false
39
23
 
40
24
  # Puts +msg+ to +@@logger+
25
+ def lflush; @@logger.flush if @@logger.respond_to? :flush; end
41
26
  def li(*msg); msg.each { |m| @@logger.puts m } if !quiet? end
42
27
  def li1(*msg); li *msg if @@loglev >= 1 end
43
28
  def li2(*msg); li *msg if @@loglev >= 2 end
@@ -71,3 +56,10 @@ module Stella
71
56
  end
72
57
  end
73
58
 
59
+ require 'stella/version'
60
+ require 'stella/exceptions'
61
+ require 'stella/utils'
62
+
63
+ Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', '*.rb')
64
+ Stella::Utils.require_vendor "httpclient", '2.1.5.2'
65
+
@@ -27,7 +27,7 @@ class Stella::CLI < Drydock::Command
27
27
  def load
28
28
  opts = {}
29
29
  opts[:hosts] = @hosts
30
- [:benchmark, :users, :repetitions, :delay, :time].each do |opt|
30
+ [:benchmark, :clients, :repetitions, :delay, :time].each do |opt|
31
31
  opts[opt] = @option.send(opt) unless @option.send(opt).nil?
32
32
  end
33
33
  ret = Stella::Engine::Load.run @testplan, opts
@@ -36,6 +36,9 @@ class Stella::CLI < Drydock::Command
36
36
 
37
37
  private
38
38
  def create_testplan
39
+ unless @option.testplan.nil? || File.exists?(@option.testplan)
40
+ raise Stella::InvalidOption, "Bad path: #{@option.testplan}"
41
+ end
39
42
  @hosts = @argv.collect { |uri|; URI.parse uri; }
40
43
  if @option.testplan
41
44
  @testplan = Stella::Testplan.load_file @option.testplan
@@ -1,6 +1,5 @@
1
1
  require "observer"
2
2
  require "tempfile"
3
- require 'httpclient'
4
3
  require 'nokogiri'
5
4
 
6
5
  module Stella
@@ -14,43 +13,52 @@ module Stella
14
13
  @base_uri, @client_id = base_uri, client_id
15
14
  @cookie_file = Tempfile.new('stella-cookie')
16
15
  @stats = Stella::Stats.new("Client #{@client_id}")
16
+ @proxy = OpenStruct.new
17
17
  end
18
18
 
19
-
20
19
  def execute(usecase)
21
- http_client = generate_http_client
20
+ http_client = create_http_client
22
21
  container = Container.new(usecase)
23
22
  counter = 0
24
23
  usecase.requests.each do |req|
25
24
  counter += 1
25
+ update(:prepare_request, usecase, req, counter)
26
+
26
27
  uri_obj = URI.parse(req.uri)
27
28
  params = prepare_params(usecase, req.params)
29
+ headers = prepare_headers(usecase, req.headers)
28
30
  uri = build_request_uri uri_obj, params, container
29
31
  raise NoHostDefined, uri_obj if uri.host.nil? || uri.host.empty?
30
32
 
33
+ unique_id = [req, params, headers, counter].gibbler
34
+ req_id = req.gibbler
35
+
31
36
  meth = req.http_method.to_s.downcase
32
- Stella.ld "#{meth}: " << "#{uri_obj.to_s} " << req.params.inspect
37
+ Stella.ld "#{req.http_method}: " << "#{uri_obj.to_s} " << params.inspect
33
38
 
34
39
  begin
35
- update(:send_request, usecase, meth, uri, req, params, counter)
36
- container.response = http_client.send(meth, uri, params) # booya!
37
- update(:receive_response, usecase, meth, uri, req, params, container)
40
+ update(:send_request, usecase, uri, req, params, container)
41
+ container.response = http_client.send(meth, uri, params, headers) # booya!
42
+ update(:receive_response, usecase, uri, req, params, container)
38
43
  rescue => ex
39
- update(:request_error, usecase, meth, uri, req, params, ex)
44
+ update(:request_error, usecase, uri, req, params, ex)
40
45
  next
41
46
  end
42
47
 
43
48
  ret = execute_response_handler container, req
44
49
 
45
- Drydock::Screen.flush
50
+ Stella.lflush
46
51
 
47
- if ret.kind_of?(ResponseModifier)
48
- case ret.class.to_s
49
- when "Stella::Client::Repeat"
50
- Stella.ld "REPETITION: #{counter} of #{ret.times+1}"
51
- redo if counter <= ret.times
52
- end
52
+ # TODO: consider throw/catch
53
+ case ret.class.to_s
54
+ when "Stella::Client::Repeat"
55
+ Stella.ld "REPETITION: #{counter} of #{ret.times+1}"
56
+ redo if counter <= ret.times
57
+ when "Stella::Client::Quit"
58
+ Stella.ld "QUIT USECASE: #{ret.message}"
59
+ break
53
60
  end
61
+
54
62
 
55
63
  counter = 0 # reset
56
64
  run_sleeper(req.wait) if req.wait && !benchmark?
@@ -63,8 +71,7 @@ module Stella
63
71
 
64
72
  private
65
73
  def update(kind, *args)
66
- changed
67
- notify_observers(kind, @client_id, *args)
74
+ changed and notify_observers(kind, @client_id, *args)
68
75
  end
69
76
 
70
77
  def run_sleeper(wait)
@@ -77,26 +84,36 @@ module Stella
77
84
  sleep ms / 1000
78
85
  end
79
86
 
80
- def generate_http_client
81
- if @proxy
82
- http_client = HTTPClient.new(@proxy.uri)
83
- http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
84
- else
85
- http_client = HTTPClient.new
86
- end
87
+ def create_http_client
88
+ opts = {
89
+ :proxy => @proxy.uri || nil, # a tautology for clarity
90
+ :agent_name => "Stella/#{Stella::VERSION}",
91
+ :from => nil
92
+ }
93
+ http_client = HTTPClient.new opts
94
+ http_client.set_proxy_auth(@proxy.user, @proxy.pass) if @proxy.user
95
+ http_client.debug_dev = STDOUT if Stella.debug? && Stella.loglev > 3
87
96
  http_client.set_cookie_store @cookie_file.to_s
97
+ #http_client.redirect_uri_callback = ??
88
98
  http_client
89
99
  end
90
100
 
91
101
  def prepare_params(usecase, params)
92
102
  newparams = {}
93
103
  params.each_pair do |n,v|
104
+ Stella.ld "PREPARE PARAM: #{n}"
94
105
  v = usecase.instance_eval &v if v.is_a?(Proc)
95
106
  newparams[n] = v
96
107
  end
97
108
  newparams
98
109
  end
99
110
 
111
+ def prepare_headers(usecase, headers)
112
+ Stella.ld "PREPARE HEADERS: #{headers}"
113
+ headers = usecase.instance_eval &headers if headers.is_a?(Proc)
114
+ headers
115
+ end
116
+
100
117
  # Testplan URIs can be relative or absolute. Either one can
101
118
  # contain variables in the form <tt>:varname</tt>, as in:
102
119
  #
@@ -146,8 +163,8 @@ module Stella
146
163
  def execute_response_handler(container, req)
147
164
  handler = nil
148
165
  req.response.each_pair do |regex,h|
166
+ Stella.ld "HANDLER REGEX: #{regex.to_s} (#{container.status})"
149
167
  regex = /#{regex}/ unless regex.is_a? Regexp
150
- Stella.ld "HANDLER REGEX: #{regex} (#{container.status})"
151
168
  handler = h and break if container.status.to_s =~ regex
152
169
  end
153
170
  ret = nil
@@ -204,7 +221,7 @@ module Stella
204
221
  def set(n, v); usecase.resource n, v; end
205
222
  def resource(n); usecase.resource n; end
206
223
  def wait(t); sleep t; end
207
-
224
+ def quit(msg=nil); Quit.new(msg); end
208
225
  def repeat(t=1); Repeat.new(t); end
209
226
  end
210
227
 
@@ -215,5 +232,11 @@ module Stella
215
232
  @times = times
216
233
  end
217
234
  end
235
+ class Quit < ResponseModifier;
236
+ attr_accessor :message
237
+ def initialize(msg=nil)
238
+ @message = msg
239
+ end
240
+ end
218
241
  end
219
242
  end
@@ -3,6 +3,26 @@ module Stella::Data
3
3
 
4
4
  module Helpers
5
5
 
6
+ def file(*args)
7
+ input = args.size > 1 ? args : args.first
8
+ Proc.new do
9
+ value = case input.class.to_s
10
+ when "String"
11
+ Stella.ld "FILE: #{input}"
12
+ path = File.exists?(input) ? input : File.join(@base_path, input)
13
+ Stella.ld "Creating file object: #{path}"
14
+ File.new(path)
15
+ when "Proc"
16
+ input.call
17
+ else
18
+ input
19
+ end
20
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
21
+ Stella.ld "FILE: #{value}"
22
+ value
23
+ end
24
+ end
25
+
6
26
  def random(*args)
7
27
  input = args.size > 1 ? args : args.first
8
28
  Proc.new do
@@ -13,6 +33,8 @@ module Stella::Data
13
33
  input
14
34
  when "Range"
15
35
  input.to_a
36
+ when "Proc"
37
+ input.call
16
38
  when "Fixnum"
17
39
  Stella::Utils.strand( input )
18
40
  when "NilClass"
@@ -28,7 +50,6 @@ module Stella::Data
28
50
 
29
51
  def sequential(*args)
30
52
  input = args.size > 1 ? args : args.first
31
- digest = input.gibbler
32
53
  Proc.new do
33
54
  value = case input.class.to_s
34
55
  when "Symbol"
@@ -38,15 +59,18 @@ module Stella::Data
38
59
  input
39
60
  when "Range"
40
61
  input.to_a
62
+ when "Proc"
63
+ input.call
41
64
  end
42
- Stella.ld "SEQVALUES: #{input} #{value.inspect}"
65
+ digest = value.gibbler
43
66
  @sequential_offset ||= {}
44
67
  @sequential_offset[digest] ||= 0
68
+ Stella.ld "SEQVALUES: #{input} #{value.inspect} #{@sequential_offset[digest]}"
45
69
  if value.is_a?(Array)
46
- size = value[ @sequential_offset[digest] ].size
70
+ size = value.size
71
+ @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
47
72
  value = value[ @sequential_offset[digest] ]
48
73
  @sequential_offset[digest] += 1
49
- @sequential_offset[digest] = 0 if @sequential_offset[digest] > size
50
74
  end
51
75
  Stella.ld "SELECTED: #{value}"
52
76
  value
@@ -55,7 +79,6 @@ module Stella::Data
55
79
 
56
80
  def rsequential(*args)
57
81
  input = args.size > 1 ? args : args.first
58
- digest = input.gibbler
59
82
  Proc.new do
60
83
  value = case input.class.to_s
61
84
  when "Symbol"
@@ -65,15 +88,18 @@ module Stella::Data
65
88
  input
66
89
  when "Range"
67
90
  input.to_a
91
+ when "Proc"
92
+ input.call
68
93
  end
69
- Stella.ld "RSEQVALUES: #{input} #{value.inspect}"
94
+ digest = value.gibbler
70
95
  @rsequential_offset ||= {}
71
96
  @rsequential_offset[digest] ||= value.size-1 rescue 1
97
+ Stella.ld "RSEQVALUES: #{input} #{value.inspect} #{@rsequential_offset[digest]}"
72
98
  if value.is_a?(Array)
73
- size = value[ @rsequential_offset[digest] ].size
99
+ size = value.size
100
+ @rsequential_offset[digest] = size-1 if @rsequential_offset[digest] < 0
74
101
  value = value[ @rsequential_offset[digest] ]
75
102
  @rsequential_offset[digest] -= 1
76
- @rsequential_offset[digest] = size if @rsequential_offset[digest] < 0
77
103
  end
78
104
  Stella.ld "SELECTED: #{value}"
79
105
  value
@@ -84,4 +110,4 @@ module Stella::Data
84
110
 
85
111
  end
86
112
 
87
- Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'data', '*.rb')
113
+ Stella::Utils.require_glob(Stella::LIB_HOME, 'stella', 'data', '*.rb')