stella 0.7.0.004 → 0.7.0.005

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +18 -5
  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
File without changes
@@ -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
data/lib/stella.rb CHANGED
@@ -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
+
data/lib/stella/cli.rb CHANGED
@@ -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
data/lib/stella/client.rb CHANGED
@@ -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
data/lib/stella/data.rb CHANGED
@@ -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')