stella 0.7.1 → 0.7.2

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.
@@ -3,36 +3,146 @@
3
3
  class Stella::Client
4
4
 
5
5
  class Container
6
+ MUTEX = Mutex.new
7
+
8
+ @sequential_offset = {}
9
+ @rsequential_offset = {}
10
+ class << self
11
+ def sequential_offset(resid, max)
12
+ MUTEX.synchronize do
13
+ @sequential_offset[resid] ||= -1
14
+ if @sequential_offset[resid] >= max
15
+ @sequential_offset[resid] = 0
16
+ else
17
+ @sequential_offset[resid] += 1
18
+ end
19
+ @sequential_offset[resid]
20
+ end
21
+ end
22
+ ## TODO: BROKEN?
23
+ ##def rsequential_offset(resid, max)
24
+ ## MUTEX.synchronize do
25
+ ## @rsequential_offset[resid] ||= max+1
26
+ ## if @rsequential_offset[resid] <= 0
27
+ ## @rsequential_offset[resid] = max
28
+ ## else
29
+ ## @rsequential_offset[resid] -= 1
30
+ ## end
31
+ ## @rsequential_offset[resid]
32
+ ## end
33
+ ##end
34
+ end
35
+
36
+ # This is used to handle custom exception in usecases.
37
+ # See examples/exceptions/plan.rb
38
+ #
39
+ def self.const_missing(custom_error)
40
+ ResponseError.new custom_error
41
+ end
42
+
6
43
 
7
44
  attr_accessor :usecase
45
+ attr_accessor :params
46
+ attr_accessor :headers
8
47
  attr_accessor :response
9
48
  attr_reader :resources
10
- def initialize(usecase)
49
+ attr_reader :client_id
50
+ attr_reader :assets
51
+
52
+ def initialize(client_id, usecase)
53
+ @client_id = client_id
11
54
  @usecase, @resources = usecase, {}
12
55
  @base_path = usecase.base_path
56
+ @assets = []
13
57
  @random_value = {}
14
58
  end
15
59
 
16
- # This is used to handle custom exception in usecases.
17
- # See examples/exceptions/plan.rb
18
- #
19
- def self.const_missing(custom_error)
20
- ResponseError.new custom_error
60
+ def params(key=nil)
61
+ key.nil? ? @params : @params[key]
62
+ end
63
+ alias_method :param, :params
64
+
65
+ def headers(key=nil)
66
+ key.nil? ? @headers : @headers[key]
67
+ end
68
+ alias_method :header, :headers
69
+
70
+ # This is intended to be called in between requests.
71
+ def reset_temp_vars
72
+ @random_value = {}
73
+ @sequential_value = {}
74
+ @rsequential_value = {}
75
+ @doc, @forms, @assets = nil, nil, []
76
+ end
77
+
78
+
79
+
80
+ def fetch(*args)
81
+ @assets.push *args.flatten
82
+ end
83
+
84
+ def parse_template(t)
85
+ # ERB BUG?: Under heavy threading, some calls
86
+ # produce the error:
87
+ # wrong number of arguments(1 for 0)
88
+ template = ERB.new(t)
89
+ v = template.result(binding)
90
+ rescue
91
+ t
21
92
  end
22
93
 
23
94
  def doc
95
+ return @doc unless @doc.nil?
24
96
  # NOTE: It's important to parse the document on every
25
97
  # request because this container is available for the
26
98
  # entire life of a usecase.
27
- case (@response.header['Content-Type'] || []).first
99
+ @doc = case (@response.header['Content-Type'] || []).first
28
100
  when /text\/html/
29
101
  Nokogiri::HTML(body)
30
102
  when /text\/xml/
31
103
  Nokogiri::XML(body)
32
104
  when /text\/yaml/
33
105
  YAML.load(body)
106
+ when /application\/json/
107
+ JSON.load(body)
108
+ end
109
+ end
110
+
111
+ class Form < Hash
112
+ def fields(key)
113
+ self['input'] ||= {}
114
+ self['input'][key]
115
+ end
116
+ alias_method :field, :fields
117
+ class << self
118
+ # Create an instance from a Nokogiri::HTML::Document
119
+ def from_doc(doc)
120
+ f = new
121
+ doc.each { |n,v| f[n] = v }
122
+ f['input'] = {}
123
+ (doc.css('input') || []).each do |input|
124
+ f['input'][input['name']] = input['value']
125
+ end
126
+ f
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ def forms(fid=nil)
133
+ if @forms.nil? && Nokogiri::HTML::Document === doc
134
+ @forms, index = {}, 0
135
+ (doc.css('form') || []).each do |html|
136
+ name = html['id'] || html['name'] || html['class']
137
+ Stella.ld [:form, name, index].inspect
138
+ # Store the form by the name and index in the document
139
+ @forms[name] = @forms[index] = Form.from_doc(html)
140
+ index += 1
141
+ end
34
142
  end
143
+ (fid.nil? ? @forms : @forms[fid])
35
144
  end
145
+ alias_method :form, :forms
36
146
 
37
147
  # Return a resource from the usecase or from this
38
148
  # container (in that order).
@@ -41,21 +151,161 @@ class Stella::Client
41
151
  return @resources[n] if @resources.has_key? n
42
152
  nil
43
153
  end
44
-
45
- def reset_temp_vars
46
- @random_value = {}
47
- @sequential_value = {}
48
- @rsequential_value = {}
49
- end
50
154
 
51
155
  def body; @response.body.content; end
52
156
  def headers; @response.header; end
53
157
  alias_method :header, :headers
54
158
  def status; @response.status; end
55
- def set(n, v); @resources[n] = v; end
159
+ def set(*args)
160
+ h = Hash === args[0] ? args[0] : {args[0]=> args[1]}
161
+ @resources.merge! h
162
+ end
56
163
  def wait(t); sleep t; end
57
164
  def quit(msg=nil); Quit.new(msg); end
165
+ def fail(msg=nil); Fail.new(msg); end
58
166
  def repeat(t=1); Repeat.new(t); end
167
+
168
+
169
+
170
+ #
171
+ # QUICK HACK ALERT:
172
+ # Copied from Stella::Data::Helpers, removed Proc.new, just return the value
173
+ #
174
+
175
+
176
+ # Can include glob
177
+ #
178
+ # e.g.
179
+ # random_file('avatar*')
180
+ def random_file(*args)
181
+ input = args.size > 1 ? args : args.first
182
+
183
+ value = case input.class.to_s
184
+ when "String"
185
+ Stella.ld "FILE: #{input}"
186
+ path = File.exists?(input) ? input : File.join(@base_path, input)
187
+ files = Dir.glob(path)
188
+ path = files[ rand(files.size) ]
189
+ Stella.ld "Creating file object: #{path}"
190
+ File.new(path)
191
+ when "Proc"
192
+ input.call
193
+ else
194
+ input
195
+ end
196
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
197
+ Stella.ld "FILE: #{value}"
198
+ value
199
+
200
+ end
201
+
202
+ def file(*args)
203
+ input = args.size > 1 ? args : args.first
204
+
205
+ value = case input.class.to_s
206
+ when "String"
207
+ Stella.ld "FILE: #{input}"
208
+ path = File.exists?(input) ? input : File.join(@base_path, input)
209
+ Stella.ld "Creating file object: #{path}"
210
+ File.new(path)
211
+ when "Proc"
212
+ input.call
213
+ else
214
+ input
215
+ end
216
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
217
+ Stella.ld "FILE: #{value}"
218
+ value
219
+
220
+ end
221
+
222
+ def random(*args)
223
+ if Symbol === args.first
224
+ input, index = *args
225
+ elsif Array === args.first || args.size == 1
226
+ input = args.first
227
+ else
228
+ input = args
229
+ end
230
+
231
+
232
+ if @random_value[input.object_id]
233
+ value = @random_value[input.object_id]
234
+ else
235
+ value = case input.class.to_s
236
+ when "Symbol"
237
+ resource(input)
238
+ when "Array"
239
+ input
240
+ when "Range"
241
+ input.to_a
242
+ when "Proc"
243
+ input.call
244
+ when "Fixnum"
245
+ Stella::Utils.strand( input )
246
+ when "NilClass"
247
+ Stella::Utils.strand( rand(100) )
248
+ end
249
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
250
+ Stella.ld "RANDVALUES: #{input} #{value.class} #{value.inspect}"
251
+ value = value[ rand(value.size) ] if value.is_a?(Array)
252
+ Stella.ld "SELECTED: #{value.class} #{value} "
253
+ @random_value[input.object_id] = value
254
+ end
255
+
256
+ # The resource may be an Array of Arrays (e.g. a CSV file)
257
+ if value.is_a?(Array) && !index.nil?
258
+ value = value[ index ]
259
+ Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
260
+ end
261
+
262
+ value
263
+
264
+ end
265
+
266
+
267
+ # NOTE: This is global across all users
268
+ def sequential(*args)
269
+ if Symbol === args.first
270
+ input, index = *args
271
+ elsif Array === args.first || args.size == 1
272
+ input = args.first
273
+ else
274
+ input = args
275
+ end
276
+
277
+ if @sequential_value[input.object_id]
278
+ value = @sequential_value[input.object_id]
279
+ else
280
+ value = case input.class.to_s
281
+ when "Symbol"
282
+ ret = resource(input)
283
+ ret
284
+ when "Array"
285
+ input
286
+ when "Range"
287
+ input.to_a
288
+ when "Proc"
289
+ input.call
290
+ end
291
+ digest = value.object_id
292
+ if value.is_a?(Array)
293
+ index = Container.sequential_offset(digest, value.size-1)
294
+ value = value[ index ]
295
+ end
296
+ Stella.ld "SELECTED(SEQ): #{value} #{index} #{input} #{digest}"
297
+ # I think this needs to be updated for global_sequential:
298
+ @sequential_value[input.object_id] = value
299
+ end
300
+ # The resource may be an Array of Arrays (e.g. a CSV file)
301
+ if value.is_a?(Array) && !index.nil?
302
+ value = value[ index ]
303
+ Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
304
+ end
305
+ value
306
+
307
+ end
308
+
59
309
  end
60
310
 
61
311
  end
@@ -15,5 +15,6 @@ class Stella::Client
15
15
  @message = msg
16
16
  end
17
17
  end
18
+ class Fail < Quit; end
18
19
 
19
20
  end
data/lib/stella/data.rb CHANGED
@@ -9,6 +9,32 @@ module Stella::Data
9
9
  end
10
10
  end
11
11
 
12
+ # Can include glob
13
+ #
14
+ # e.g.
15
+ # random_file('avatar*')
16
+ def random_file(*args)
17
+ input = args.size > 1 ? args : args.first
18
+ Proc.new do
19
+ value = case input.class.to_s
20
+ when "String"
21
+ Stella.ld "FILE: #{input}"
22
+ path = File.exists?(input) ? input : File.join(@base_path, input)
23
+ files = Dir.glob(path)
24
+ path = files[ rand(files.size) ]
25
+ Stella.ld "Creating file object: #{path}"
26
+ File.new(path)
27
+ when "Proc"
28
+ input.call
29
+ else
30
+ input
31
+ end
32
+ raise Stella::Testplan::Usecase::UnknownResource, input if value.nil?
33
+ Stella.ld "FILE: #{value}"
34
+ value
35
+ end
36
+ end
37
+
12
38
  def file(*args)
13
39
  input = args.size > 1 ? args : args.first
14
40
  Proc.new do
@@ -39,8 +65,8 @@ module Stella::Data
39
65
  end
40
66
 
41
67
  Proc.new do
42
- if @random_value[input]
43
- value = @random_value[input]
68
+ if @random_value[input.object_id]
69
+ value = @random_value[input.object_id]
44
70
  else
45
71
  value = case input.class.to_s
46
72
  when "Symbol"
@@ -60,7 +86,7 @@ module Stella::Data
60
86
  Stella.ld "RANDVALUES: #{input} #{value.class} #{value.inspect}"
61
87
  value = value[ rand(value.size) ] if value.is_a?(Array)
62
88
  Stella.ld "SELECTED: #{value.class} #{value} "
63
- @random_value[input] = value
89
+ @random_value[input.object_id] = value
64
90
  end
65
91
 
66
92
  # The resource may be an Array of Arrays (e.g. a CSV file)
@@ -73,6 +99,8 @@ module Stella::Data
73
99
  end
74
100
  end
75
101
 
102
+
103
+ # NOTE: This is global across all users
76
104
  def sequential(*args)
77
105
  if Symbol === args.first
78
106
  input, index = *args
@@ -82,8 +110,8 @@ module Stella::Data
82
110
  input = args
83
111
  end
84
112
  Proc.new do
85
- if @sequential_value[input]
86
- value = @sequential_value[input]
113
+ if @sequential_value[input.object_id]
114
+ value = @sequential_value[input.object_id]
87
115
  else
88
116
  value = case input.class.to_s
89
117
  when "Symbol"
@@ -96,18 +124,14 @@ module Stella::Data
96
124
  when "Proc"
97
125
  input.call
98
126
  end
99
- digest = value.gibbler
100
- @sequential_offset ||= {}
101
- @sequential_offset[digest] ||= 0
102
- Stella.ld "SEQVALUES: #{input} #{value.inspect} #{@sequential_offset[digest]}"
127
+ digest = value.object_id
103
128
  if value.is_a?(Array)
104
- size = value.size
105
- @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
106
- value = value[ @sequential_offset[digest] ]
107
- @sequential_offset[digest] += 1
129
+ index = Container.sequential_offset(digest, value.size-1)
130
+ value = value[ index ]
108
131
  end
109
- Stella.ld "SELECTED: #{value}"
110
- @sequential_value[input] = value
132
+ Stella.ld "SELECTED(SEQ): #{value} #{index} #{input} #{digest}"
133
+ # I think this needs to be updated for global_sequential:
134
+ @sequential_value[input.object_id] = value
111
135
  end
112
136
  # The resource may be an Array of Arrays (e.g. a CSV file)
113
137
  if value.is_a?(Array) && !index.nil?
@@ -118,53 +142,150 @@ module Stella::Data
118
142
  end
119
143
  end
120
144
 
121
- def rsequential(*args)
122
- if Symbol === args.first
123
- input, index = *args
124
- elsif Array === args.first || args.size == 1
125
- input = args.first
126
- else
127
- input = args
128
- end
129
- Proc.new do
130
- if @rsequential_value[input.digest]
131
- value = @rsequential_value[input.digest]
132
- else
133
- value = case input.class.to_s
134
- when "Symbol"
135
- ret = resource(input)
136
- ret
137
- when "Array"
138
- input
139
- when "Range"
140
- input.to_a
141
- when "Proc"
142
- input.call
143
- end
144
- digest = value.gibbler
145
- @rsequential_offset ||= {}
146
- @rsequential_offset[digest] ||= value.size-1 rescue 1
147
- Stella.ld "RSEQVALUES: #{input} #{value.inspect} #{@rsequential_offset[digest]}"
148
- if value.is_a?(Array)
149
- size = value.size
150
- @rsequential_offset[digest] = size-1 if @rsequential_offset[digest] < 0
151
- value = value[ @rsequential_offset[digest] ]
152
- @rsequential_offset[digest] -= 1
153
- end
154
- Stella.ld "SELECTED: #{value}"
155
- @rsequential_value[input.digest] = value
156
- end
157
-
158
- # The resource may be an Array of Arrays (e.g. a CSV file)
159
- if value.is_a?(Array) && !index.nil?
160
- value = value[ index ]
161
- Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
162
- end
163
-
164
- value
165
- end
166
- end
167
145
 
146
+ ###
147
+ ### Disabled b/c it doesn't work anymore since a
148
+ ### new Container is created for every repetition.
149
+ ###
150
+ ##def sequential(*args)
151
+ ## if Symbol === args.first
152
+ ## input, index = *args
153
+ ## elsif Array === args.first || args.size == 1
154
+ ## input = args.first
155
+ ## else
156
+ ## input = args
157
+ ## end
158
+ ## Proc.new do
159
+ ## if @sequential_value[input]
160
+ ## value = @sequential_value[input]
161
+ ## else
162
+ ## value = case input.class.to_s
163
+ ## when "Symbol"
164
+ ## ret = resource(input)
165
+ ## ret
166
+ ## when "Array"
167
+ ## input
168
+ ## when "Range"
169
+ ## input.to_a
170
+ ## when "Proc"
171
+ ## input.call
172
+ ## end
173
+ ## digest = value.object_id
174
+ ## @sequential_offset ||= {}
175
+ ## @sequential_offset[digest] ||= 0
176
+ ## Stella.ld "SEQVALUES: #{@sequential_offset.object_id} #{value.inspect} #{@sequential_offset[digest]}"
177
+ ## if value.is_a?(Array)
178
+ ## size = value.size
179
+ ## @sequential_offset[digest] = 0 if @sequential_offset[digest] >= size
180
+ ## value = value[ @sequential_offset[digest] ]
181
+ ## Stella.li "WHAY: #{value} (#{@sequential_offset[digest]})"
182
+ ## @sequential_offset[digest] += 1
183
+ ## end
184
+ ## Stella.ld "SELECTED: #{value}"
185
+ ## @sequential_value[input] = value
186
+ ## end
187
+ ## # The resource may be an Array of Arrays (e.g. a CSV file)
188
+ ## if value.is_a?(Array) && !index.nil?
189
+ ## value = value[ index ]
190
+ ## Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
191
+ ## end
192
+ ## value
193
+ ## end
194
+ ##end
195
+ ##
196
+ ##def rsequential(*args)
197
+ ## if Symbol === args.first
198
+ ## input, index = *args
199
+ ## elsif Array === args.first || args.size == 1
200
+ ## input = args.first
201
+ ## else
202
+ ## input = args
203
+ ## end
204
+ ## Proc.new do
205
+ ## if @rsequential_value[input.digest]
206
+ ## value = @rsequential_value[input.digest]
207
+ ## else
208
+ ## value = case input.class.to_s
209
+ ## when "Symbol"
210
+ ## ret = resource(input)
211
+ ## ret
212
+ ## when "Array"
213
+ ## input
214
+ ## when "Range"
215
+ ## input.to_a
216
+ ## when "Proc"
217
+ ## input.call
218
+ ## end
219
+ ## digest = value.object_id
220
+ ## @rsequential_offset ||= {}
221
+ ## Stella.ld "RSEQVALUES: #{input} #{value.inspect}"
222
+ ## if value.is_a?(Array)
223
+ ## size = value.size
224
+ ## @rsequential_offset[digest] ||= size-1
225
+ ## @rsequential_offset[digest] = size-1 if @rsequential_offset[digest] < 0
226
+ ## value = value[ @rsequential_offset[digest] ]
227
+ ## @rsequential_offset[digest] -= 1
228
+ ## end
229
+ ## Stella.ld "SELECTED: #{value}"
230
+ ## @rsequential_value[input.digest] = value
231
+ ## end
232
+ ##
233
+ ## # The resource may be an Array of Arrays (e.g. a CSV file)
234
+ ## if value.is_a?(Array) && !index.nil?
235
+ ## value = value[ index ]
236
+ ## Stella.ld "SELECTED INDEX: #{index} #{value.inspect} "
237
+ ## end
238
+ ##
239
+ ## value
240
+ ## end
241
+ ##end
242
+
243
+
244
+
245
+ # NOTE: This is global across all users
246
+ ## TODO: Broken??
247
+ ##def rsequential(*args)
248
+ ## if Symbol === args.first
249
+ ## input, index = *args
250
+ ## elsif Array === args.first || args.size == 1
251
+ ## input = args.first
252
+ ## else
253
+ ## input = args
254
+ ## end
255
+ ## Proc.new do
256
+ ## if @rsequential_value[input.object_id]
257
+ ## value = @rsequential_value[input.object_id]
258
+ ## else
259
+ ## value = case input.class.to_s
260
+ ## when "Symbol"
261
+ ## ret = resource(input)
262
+ ## ret
263
+ ## when "Array"
264
+ ## input
265
+ ## when "Range"
266
+ ## input.to_a
267
+ ## when "Proc"
268
+ ## input.call
269
+ ## end
270
+ ## digest = value.object_id
271
+ ## if value.is_a?(Array)
272
+ ## index = Container.rsequential_offset(digest, value.size-1)
273
+ ## value = value[ index ]
274
+ ## end
275
+ ## Stella.ld "SELECTED(RSEQ): #{value} #{index} #{input} #{digest}"
276
+ ## # I think this needs to be updated for global_rsequential:
277
+ ## @rsequential_value[input.object_id] = value
278
+ ## end
279
+ ##
280
+ ## # The resource may be an Array of Arrays (e.g. a CSV file)
281
+ ## if value.is_a?(Array) && !index.nil?
282
+ ## value = value[ index ]
283
+ ## Stella.ld "SELECTED INDEX: #{index} #{value.inspect} #{input} #{digest}"
284
+ ## end
285
+ ##
286
+ ## value
287
+ ## end
288
+ ##end
168
289
  end
169
290
 
170
291
  end