stella 0.7.1 → 0.7.2

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