stella 0.7.3.002 → 0.7.4.001

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.
@@ -45,6 +45,7 @@ class Stella::Client
45
45
  attr_accessor :params
46
46
  attr_accessor :headers
47
47
  attr_accessor :response
48
+ attr_accessor :unique_id
48
49
  attr_reader :resources
49
50
  attr_reader :client_id
50
51
  attr_reader :assets
@@ -87,7 +88,8 @@ class Stella::Client
87
88
  # wrong number of arguments(1 for 0)
88
89
  template = ERB.new(t)
89
90
  v = template.result(binding)
90
- rescue
91
+ rescue => ex
92
+ Stella.ld ex.message, ex.backtrace
91
93
  t
92
94
  end
93
95
 
@@ -163,6 +165,7 @@ class Stella::Client
163
165
  def wait(t); sleep t; end
164
166
  def quit(msg=nil); Quit.new(msg); end
165
167
  def fail(msg=nil); Fail.new(msg); end
168
+ def error(msg=nil); Error.new(msg); end
166
169
  def repeat(t=1); Repeat.new(t); end
167
170
 
168
171
 
@@ -0,0 +1,255 @@
1
+ #encoding: utf-8
2
+
3
+ $KCODE = "u" if RUBY_VERSION =~ /^1.8/
4
+
5
+
6
+
7
+ # Assumes Time::Units and Numeric mixins are available.
8
+
9
+ class String
10
+
11
+ def in_seconds
12
+ # "60m" => ["60", "m"]
13
+ q,u = self.scan(/([\d\.]+)([s,m,h])?/).flatten
14
+ q &&= q.to_f and u ||= 's'
15
+ q &&= q.in_seconds(u)
16
+ end
17
+
18
+ end
19
+
20
+ class MatchData
21
+ include Gibbler::String
22
+ end
23
+
24
+ class Thread
25
+ extend Attic
26
+ attic :stats
27
+ end
28
+
29
+ class Time
30
+ module Units
31
+ PER_MICROSECOND = 0.000001.freeze
32
+ PER_MILLISECOND = 0.001.freeze
33
+ PER_MINUTE = 60.0.freeze
34
+ PER_HOUR = 3600.0.freeze
35
+ PER_DAY = 86400.0.freeze
36
+
37
+ def microseconds() seconds * PER_MICROSECOND end
38
+ def milliseconds() seconds * PER_MILLISECOND end
39
+ def seconds() self end
40
+ def minutes() seconds * PER_MINUTE end
41
+ def hours() seconds * PER_HOUR end
42
+ def days() seconds * PER_DAY end
43
+ def weeks() seconds * PER_DAY * 7 end
44
+ def years() seconds * PER_DAY * 365 end
45
+
46
+ def in_years() seconds / PER_DAY / 365 end
47
+ def in_weeks() seconds / PER_DAY / 7 end
48
+ def in_days() seconds / PER_DAY end
49
+ def in_hours() seconds / PER_HOUR end
50
+ def in_minutes() seconds / PER_MINUTE end
51
+ def in_milliseconds() seconds / PER_MILLISECOND end
52
+ def in_microseconds() seconds / PER_MICROSECOND end
53
+
54
+ def in_seconds(u=nil)
55
+ case u.to_s
56
+ when /\A(y)|(years?)\z/
57
+ years
58
+ when /\A(w)|(weeks?)\z/
59
+ weeks
60
+ when /\A(d)|(days?)\z/
61
+ days
62
+ when /\A(h)|(hours?)\z/
63
+ hours
64
+ when /\A(m)|(minutes?)\z/
65
+ minutes
66
+ when /\A(ms)|(milliseconds?)\z/
67
+ milliseconds
68
+ when /\A(us)|(microseconds?)|(μs)\z/
69
+ microseconds
70
+ else
71
+ self
72
+ end
73
+ end
74
+
75
+ ## JRuby doesn't like using instance_methods.select here.
76
+ ## It could be a bug or something quirky with Attic
77
+ ## (although it works in 1.8 and 1.9). The error:
78
+ ##
79
+ ## lib/attic.rb:32:in `select': yield called out of block (LocalJumpError)
80
+ ## lib/stella/mixins/numeric.rb:24
81
+ ##
82
+ ## Create singular methods, like hour and day.
83
+ # instance_methods.select.each do |plural|
84
+ # singular = plural.to_s.chop
85
+ # alias_method singular, plural
86
+ # end
87
+
88
+ alias_method :ms, :milliseconds
89
+ alias_method :'μs', :microseconds
90
+ alias_method :second, :seconds
91
+ alias_method :minute, :minutes
92
+ alias_method :hour, :hours
93
+ alias_method :day, :days
94
+ alias_method :week, :weeks
95
+ alias_method :year, :years
96
+
97
+ end
98
+ end
99
+
100
+ class Numeric
101
+ include Time::Units
102
+ # TODO: Use 1024?
103
+ def to_bytes
104
+ args = case self.abs.to_i
105
+ when 0..1000
106
+ [(self).to_s, 'B']
107
+ when (1000)..(1000**2)
108
+ [(self / 1000.to_f).to_s, 'KB']
109
+ when (1000**2)..(1000**3)
110
+ [(self / (1000**2).to_f).to_s, 'MB']
111
+ when (1000**3)..(1000**4)
112
+ [(self / (1000**3).to_f).to_s, 'GB']
113
+ when (1000**4)..(1000**6)
114
+ [(self / (1000**4).to_f).to_s, 'TB']
115
+ else
116
+ [self, 'B']
117
+ end
118
+ '%3.2f%s' % args
119
+ end
120
+ end
121
+
122
+
123
+
124
+
125
+
126
+ class Stella::Config < Storable
127
+ include Gibbler::Complex
128
+
129
+ field :source
130
+ field :apikey
131
+ field :secret
132
+
133
+ field :redis_host
134
+ field :redis_port
135
+ field :redis_pass
136
+
137
+ # Returns true when the current config matches the default config
138
+ def default?; to_hash.gibbler == DEFAULT_CONFIG_HASH; end
139
+
140
+ def self.each_path(&blk)
141
+ [PROJECT_PATH, USER_PATH].each do |path|
142
+ Stella.ld "Loading #{path}"
143
+ blk.call(path) if File.exists? path
144
+ end
145
+ end
146
+
147
+ def self.refresh
148
+ conf = {}
149
+ Stella::Config.each_path do |path|
150
+ tmp = YAML.load_file path
151
+ conf.merge! tmp if tmp
152
+ end
153
+ a = from_hash conf
154
+ a || new
155
+ end
156
+
157
+ def self.init
158
+ raise AlreadyInitialized, PROJECT_PATH if File.exists? PROJECT_PATH
159
+ dir = File.dirname USER_PATH
160
+ Dir.mkdir(dir, 0700) unless File.exists? dir
161
+ unless File.exists? USER_PATH
162
+ Stella.stdout.info "Creating #{USER_PATH} (Add your credentials here)"
163
+ Stella::Utils.write_to_file(USER_PATH, DEFAULT_CONFIG, 'w', 0600)
164
+ end
165
+
166
+ dir = File.dirname PROJECT_PATH
167
+ Dir.mkdir(dir, 0700) unless File.exists? dir
168
+
169
+ Stella.stdout.info "Creating #{PROJECT_PATH}"
170
+ Stella::Utils.write_to_file(PROJECT_PATH, 'target:', 'w', 0600)
171
+ end
172
+
173
+ def self.blast
174
+ if File.exists? USER_PATH
175
+ Stella.stdout.info "Blasting #{USER_PATH}"
176
+ FileUtils.rm_rf File.dirname(USER_PATH)
177
+ end
178
+ if File.exists? PROJECT_PATH
179
+ Stella.stdout.info "Blasting #{PROJECT_PATH}"
180
+ FileUtils.rm_rf File.dirname(PROJECT_PATH)
181
+ end
182
+ end
183
+
184
+ def self.project_dir
185
+ File.join(Dir.pwd, DIR_NAME)
186
+ end
187
+
188
+ private
189
+
190
+ def self.find_project_config
191
+ dir = Dir.pwd.split File::SEPARATOR
192
+ path = nil
193
+ while !dir.empty?
194
+ tmp = File.join(dir.join(File::SEPARATOR), DIR_NAME, 'config')
195
+ Stella.ld " -> looking for #{tmp}"
196
+ path = tmp and break if File.exists? tmp
197
+ dir.pop
198
+ end
199
+ path ||= File.join(Dir.pwd, DIR_NAME, 'config')
200
+ path
201
+ end
202
+
203
+
204
+ unless defined?(DIR_NAME)
205
+ DIR_NAME = Stella.sysinfo.os == :windows ? 'Stella' : '.stella'
206
+ USER_PATH = File.join(Stella.sysinfo.home, DIR_NAME, 'config')
207
+ PROJECT_PATH = Stella::Config.find_project_config
208
+ DEFAULT_CONFIG = <<CONF
209
+ apikey: ''
210
+ secret: ''
211
+ remote: stella.solutious.com:443
212
+ CONF
213
+ DEFAULT_CONFIG_HASH = YAML.load(DEFAULT_CONFIG).gibbler
214
+ end
215
+
216
+ class AlreadyInitialized < Stella::Error; end
217
+ end
218
+
219
+
220
+
221
+ module Stella
222
+ class Hand
223
+ attr_accessor :force_stop
224
+ attr_reader :dthread
225
+
226
+ def initialize(freq=4, rest=1, &routine)
227
+ @freq, @rest, @routine = freq, rest, routine
228
+ end
229
+
230
+ def stop()
231
+ @force_stop = true
232
+ @dthread.join
233
+ @routine.call
234
+ end
235
+ def stop?() @force_stop == true end
236
+
237
+ # Execute yield every FREQUENCY seconds.
238
+ def start
239
+ @dthread ||= Thread.new do
240
+ prev_ptime = Time.now
241
+ loop do
242
+ break if Stella.abort? || stop?
243
+ if (Time.now - prev_ptime).to_i >= @freq
244
+ @routine.call
245
+ prev_ptime = Time.now
246
+ end
247
+ sleep @rest
248
+ end
249
+ end
250
+ @dthread.abort_on_exception = true
251
+ end
252
+ end
253
+ end
254
+
255
+
data/lib/stella/data.rb CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
2
  module Stella::Data
3
+ extend self
3
4
 
4
5
  module Helpers
5
6
 
@@ -126,10 +127,11 @@ module Stella::Data
126
127
  end
127
128
  digest = value.object_id
128
129
  if value.is_a?(Array)
129
- index = Stella::Client::Container.sequential_offset(digest, value.size-1)
130
- value = value[ index ]
130
+ idx = Stella::Client::Container.sequential_offset(digest, value.size-1)
131
+ value = value[ idx ]
132
+ Stella.ld "SELECTED(SEQ): #{value} #{idx} #{input} #{digest}"
131
133
  end
132
- Stella.ld "SELECTED(SEQ): #{value} #{index} #{input} #{digest}"
134
+
133
135
  # I think this needs to be updated for global_sequential:
134
136
  @sequential_value[input.object_id] = value
135
137
  end
@@ -178,7 +180,7 @@ module Stella::Data
178
180
  ## size = value.size
179
181
  ## @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
180
182
  ## value = value[ @sequential_offset[digest] ]
181
- ## Stella.li "WHAY: #{value} (#{@sequential_offset[digest]})"
183
+ ## Stella.stdout.info "WHAY: #{value} (#{@sequential_offset[digest]})"
182
184
  ## @sequential_offset[digest] += 1
183
185
  ## end
184
186
  ## Stella.ld "SELECTED: #{value}"
@@ -1,4 +1,128 @@
1
1
 
2
- module Stella::Data::HTTP; end
3
2
 
4
- Stella::Utils.require_glob(STELLA_LIB_HOME, 'stella', 'data', 'http', '*.rb')
3
+ module Stella::Data::HTTP
4
+ class Request < Storable
5
+ include Gibbler::Complex
6
+ include Stella::Data::Helpers
7
+
8
+ # A hash containing blocks to be executed depending on the HTTP response status.
9
+ # The hash keys are numeric HTTP Status Codes.
10
+ #
11
+ # 200 => { ... }
12
+ # 304 => { ... }
13
+ # 500 => { ... }
14
+ #
15
+ attr_accessor :response_handler
16
+
17
+ field :desc
18
+ field :header
19
+ field :uri
20
+ field :wait
21
+ field :params
22
+ field :body
23
+ field :http_method
24
+ field :http_version
25
+ field :content_type
26
+ field :http_auth
27
+
28
+ def has_body?
29
+ !@body.nil?
30
+ end
31
+
32
+ def initialize (method, uri_str, version="1.1", &definition)
33
+ @uri = uri_str
34
+ @http_method, @http_version = method, version
35
+ @headers, @params, @response_handler = {}, {}, {}
36
+ @resources = {}
37
+ @wait = 0
38
+ @desc = "Request"
39
+ instance_eval &definition unless definition.nil?
40
+ end
41
+
42
+ def auth(user=nil, pass=nil, kind=:basic)
43
+ @http_auth ||= Stella::Testplan::Usecase::Auth.new
44
+ @http_auth.user, @http_auth.pass, @http_auth.kind = user, pass, kind
45
+ end
46
+
47
+ def desc(*args)
48
+ @desc = args.first unless args.empty?
49
+ @desc
50
+ end
51
+
52
+ def content_type(*args)
53
+ @content_type = args.first unless args.empty?
54
+ @content_type
55
+ end
56
+
57
+ def wait(*args)
58
+ @wait = args.first unless args.empty?
59
+ @wait
60
+ end
61
+ alias_method :sleep, :wait
62
+
63
+ def headers(*args)
64
+ unless args.empty?
65
+ h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
66
+ @headers.merge! h unless h.empty?
67
+ end
68
+ @headers
69
+ end
70
+ alias_method :header, :headers
71
+
72
+ # Set a resource key value pair in the get, post block.
73
+ # These will be process later in Stella::Client
74
+ def set(*args)
75
+ unless args.empty?
76
+ h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
77
+ @resources.merge! h unless h.empty?
78
+ end
79
+ @resources
80
+ end
81
+ alias_method :resources, :set
82
+
83
+ def params(*args)
84
+ unless args.empty?
85
+ h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
86
+ @params.merge! h unless h.empty?
87
+ end
88
+ @params
89
+ end
90
+ alias_method :param, :params
91
+
92
+ def response(*args, &definition)
93
+ if definition.nil?
94
+ @response_handler
95
+ else
96
+ args << /.+/ if args.empty?
97
+ args.each do |status|
98
+ @response_handler[status] = definition
99
+ end
100
+ end
101
+ end
102
+
103
+ # +content+ can be literal content or a file path
104
+ def body(*args)
105
+ return @body if args.empty?
106
+ @body = args.first
107
+ end
108
+
109
+ def inspect
110
+ str = "%s %s" % [http_method, uri.to_s, http_version]
111
+ #str << $/ + headers.join($/) unless headers.empty?
112
+ #str << $/ + $/ + body.to_s if body
113
+ str
114
+ end
115
+
116
+ def to_s
117
+ str = "%s %s" % [http_method, uri.to_s, http_version]
118
+ str
119
+ end
120
+
121
+ def cookies
122
+ return [] if !header.is_a?(Hash) || header[:Cookie].empty?
123
+ header[:Cookie]
124
+ end
125
+
126
+ end
127
+
128
+ end
data/lib/stella/engine.rb CHANGED
@@ -17,8 +17,23 @@ module Stella::Engine
17
17
  end
18
18
  end
19
19
 
20
- def runid
21
-
20
+ def runid(plan)
21
+ args = [Stella.sysinfo.hostname, Stella.sysinfo.user]
22
+ args.push Stella::START_TIME, plan
23
+ args.digest
24
+ end
25
+
26
+ def log_dir(plan, file=nil)
27
+ stamp = Stella::START_TIME.strftime("%Y%m%d-%H-%M-%S")
28
+ stamp <<"-#{plan.digest.short}"
29
+ #stamp << "STAMP"
30
+ l = File.join Stella::Config.project_dir, 'log', stamp
31
+ FileUtils.mkdir_p l unless File.exists? l
32
+ l
33
+ end
34
+
35
+ def log_path(plan, file)
36
+ File.join log_dir(plan), file
22
37
  end
23
38
 
24
39
  def process_options!(plan, opts={})
@@ -31,13 +46,12 @@ module Stella::Engine
31
46
  :repetitions => 1
32
47
  }.merge! opts
33
48
 
34
- Stella.li3 " Options: #{opts.inspect}"
35
- Stella.lflush
49
+ Stella.stdout.info2 " Options: #{opts.inspect}"
36
50
 
37
51
  opts[:clients] = plan.usecases.size if opts[:clients] < plan.usecases.size
38
52
 
39
53
  if opts[:clients] > @@client_limit
40
- Stella.li2 "Client limit is #{@@client_limit}"
54
+ Stella.stdout.info2 "Client limit is #{@@client_limit}"
41
55
  opts[:clients] = @@client_limit
42
56
  end
43
57
 
@@ -48,13 +62,13 @@ module Stella::Engine
48
62
 
49
63
  opts[:duration] = opts[:duration].in_seconds
50
64
 
51
- Stella.li3 " Hosts: " << opts[:hosts].join(', ')
65
+ Stella.stdout.info3 " Hosts: " << opts[:hosts].join(', ')
52
66
  opts
53
67
  end
54
68
 
55
69
  def run; raise; end
56
- def update_quit_usecase(client_id, msg) raise end
57
- def update_repeat_request(client_id, counter, total) raise end
70
+ def update_usecase_quit(client_id, msg) raise end
71
+ def update_request_repeat(client_id, counter, total) raise end
58
72
  def update_stats(client_id, http_client, usecase, req) raise end
59
73
  def update_prepare_request(*args) raise end
60
74
  def update_send_request(*args) raise end
@@ -62,6 +76,8 @@ module Stella::Engine
62
76
  def update_execute_response_handler(*args) raise end
63
77
  def update_error_execute_response_handler(*args) raise end
64
78
  def update_request_error(*args) raise end
79
+ def request_unhandled_exception(*args) raise end
80
+ def update_request_fail(*args) raise end
65
81
 
66
82
  end
67
83
 
@@ -70,6 +86,7 @@ module Stella::Engine
70
86
  autoload :LoadPackage, 'stella/engine/load_package'
71
87
  autoload :LoadCreate, 'stella/engine/load_create'
72
88
  autoload :LoadQueue, 'stella/engine/load_queue'
89
+ autoload :LoadRedis, 'stella/engine/load_redis'
73
90
 
74
91
  # These timers are interesting from a reporting perspective.
75
92
  Benelux.add_counter Stella::Client, :execute_response_handler