stella 0.7.3.002 → 0.7.4.001

Sign up to get free protection for your applications and to get access to all the features.
@@ -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