Module: RWebSpec::Mechanize::LoadTestHelper

Includes:
Assert, LoadWisePlugin, Utils
Defined in:
lib/rwebspec-mechanize/load_test_helper.rb

Constant Summary collapse

MAX_VU =
10001

Constants included from Utils

Utils::WORDS

Instance Method Summary collapse

Methods included from LoadWisePlugin

#connect_to_loadwise, #debug, #dump_caller_stack, #notify_screenshot_location, #operation_delay

Methods included from Assert

#assert_button_not_present, #assert_button_not_present_with_text, #assert_button_present, #assert_button_present_with_text, #assert_checkbox_not_selected, #assert_checkbox_selected, #assert_equals, #assert_exists, #assert_hidden, #assert_link_not_present_with_exact, #assert_link_not_present_with_text, #assert_link_present_with_exact, #assert_link_present_with_text, #assert_nil, #assert_not, #assert_not_exists, #assert_not_nil, #assert_option_equals, #assert_option_not_present, #assert_option_present, #assert_option_value_equals, #assert_option_value_not_present, #assert_option_value_present, #assert_radio_option_not_present, #assert_radio_option_not_selected, #assert_radio_option_present, #assert_radio_option_selected, #assert_text_field_value, #assert_text_in_element, #assert_text_in_page_source, #assert_text_not_in_page_source, #assert_text_not_present, #assert_text_not_present_in_table, #assert_text_present, #assert_text_present_in_table, #assert_title_equals, #assert_visible, #fail

Methods included from Utils

#days_before, #days_from_now, #interpret_value, #on, #paragraphs, #random_boolean, #random_char, #random_digit, #random_number, #random_str, #random_string_in, #repeat_try, #sentences, #shall_not_allow, #take_screenshot, #today, #tomorrow, #try, #value_in_range, #words, #yesterday

Instance Method Details

#allow(&block) ⇒ Object Also known as: shall_allow, allowing

Does not provide real function, other than make enhancing test syntax

Example:

allow { click_button('Register') }


60
61
62
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 60

def allow(&block)
  yield
end

#append_test_result(vu, test_file, description, started_at, duration) ⇒ Object



180
181
182
183
184
185
186
187
188
189
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 180

def append_test_result(vu, test_file, description, started_at, duration)
  return if RUBY_PLATFORM =~ /java/
  init_memory_database if $memory_db.nil?
				begin
  $memory_db.execute("insert into load_test_stats (virtual_user, test_file, description, started_at, duration, ended_at) values (?, ?, ?, ?, ?, ?)", vu, "", description, started_at, duration, Time.now.to_i)
				rescue => e
					puts "[WARN] Failed to append test results: #{vu}|#{test_file}|#{description}|#{started_at}|#{duration}\n#{e} => #{e.backtrace}"
				end
				
end

#failsafe(&block) ⇒ Object Also known as: fail_safe

try operation, ignore if errors occur

Example:

failsafe { click_link("Logout") }  # try logout, but it still OK if not being able to (already logout))


70
71
72
73
74
75
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 70

def failsafe(&block)
  begin
    yield
  rescue =>e
  end
end

#init_memory_database(force = true) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 155

def init_memory_database(force = true)
  # Open a database
  require 'sqlite3'
  if $memory_db.nil? || force
    $memory_db = SQLite3::Database.new ":memory:"
  

    # Create a database
    rows = $memory_db.execute "
      create table load_test_stats (
        id integer PRIMARY KEY,
        virtual_user varchar(64),
        test_file varchar(256),
        description varchar(256),          
        started_at integer,
        duration decimal(6, 2),
        ended_at integer
      );"
  end

end

#log_time(msg, &block) ⇒ Object

monitor current execution using

Usage

log_time { browser.click_button('Confirm') }


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 125

def log_time(msg, &block)
  start_time = Time.now
  begin; 
					dump_caller_stack; 
				rescue; 
				end;

  Thread.current[:log] ||= []
  begin
yield

   Thread.current[:log] << {:file => File.basename(__FILE__),
     :message => msg,
     :start_time => Time.now,
     :duration => Time.now - start_time}

				rescue => e

   Thread.current[:log] << {:file => File.basename(__FILE__),
     :message => msg + " => Failed",
     :start_time => Time.now,
     :duration => Time.now - start_time}
				ensure
					end_time = Time.now	        
					format_date_time = start_time.strftime("%Y-%m-%d %H:%M:%S")
					connect_to_loadwise("  LOAD", "#{Thread.current[:id]}|#{msg}|#{format_date_time}|#{Time.now - start_time}")
				end

end

#open_browser(base_url = nil, options = {}) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 16

def open_browser(base_url = nil, options = {})
  default_options = {:resynchronize => false, :go => false }      
  options = default_options.merge(options)

  base_url ||= $LOADWISE_PROJECT_BASE_URL        
				if RUBY_PLATFORM =~ /java/
  	base_url ||= ENV["LOADWISE_PROJECT_BASE_URL"] # pass to java
				end
  base_url ||= $BASE_URL
  # puts "[DEBUG] open |#{base_url}|#{$BASE_URL}| in browser"

  mode_preview = ($LOADWISE_PREVIEW || ENV['LOADWISE_PREVIEW'])
  
  unless mode_preview
    RWebSpec::Mechanize::WebBrowser.new(base_url, nil, options)
  else
    if RUBY_PLATFORM =~ /mingw/
      puts "loading RWEBSPEC..."
      require 'rwebspec'
RWebSpec.framework = "Watir"
      RWebSpec::WebBrowser.new(base_url, nil, options)          
    else 
      require 'rwebspec'         
RWebSpec.framework = "Selenium-WebDriver"
if RUBY_PLATFORM =~ /darwin/ 
  if File.exists?("/usr/bin/chromedriver") && File.exists?("/usr/local/bin/chromedriver") 						    
	  options[:browser] = "chrome" 
  else
	  options[:browser] = "firefox" 
   end
 else
   options[:browser] = "firefox"
end
      RWebSpec::WebBrowser.new(base_url, nil, options)
    end
  end
end

#run_with_virtual_users(opts = {}, &block) ⇒ Object

How many virtual users should be running immedately

:start_virtual_user_count  

How many threads should be running at peak load.
:peak_virtual_user_count

How many seconds to wait between starting threads.

:delay_between_thread_start

How many minutes the test should run with all threads active. TIME_AT_PEAK_QPS = 10 # minutes

Defaults: :start_virtual_user_count => 1, :peak_virtual_user_count => 3, :delay_between_thread_start => 10



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 208

def run_with_virtual_users(opts = {}, &block)
  
  init_memory_database unless RUBY_PLATFORM =~ /java/
  $vu_error_printed = false

  if $load_runtime_options          
    default_opts = $load_runtime_options
				else				
   if RUBY_PLATFORM =~ /java/
     default_opts = {}
     default_opts[:start_virtual_user_count] = ENV["LOADWISE_START_VIRTUAL_USER_COUNT"].to_i if  ENV["LOADWISE_START_VIRTUAL_USER_COUNT"]
     default_opts[:peak_virtual_user_count] = ENV["LOADWISE_PEAK_VIRTUAL_USER_COUNT"].to_i if  ENV["LOADWISE_PEAK_VIRTUAL_USER_COUNT"]
     default_opts[:delay_between_thread_start] = ENV["LOADWISE_DELAY_BETWEEN_THREAD_START"].to_i if  ENV["LOADWISE_DELAY_BETWEEN_THREAD_START"]     
     default_opts[:for_how_long] = ENV["LOADWISE_FOR_HOW_LONG"].to_i if  ENV["LOADWISE_FOR_HOW_LONG"]
     default_opts[:virtual_user_count_per_rampup] = ENV["LOADWISE_VIRTUAL_USER_COUNT_PER_RAMPUP"].to_i if  ENV["LOADWISE_VIRTUAL_USER_COUNT_PER_RAMPUP"]
  	else
# default to performance testing
      default_opts = {:start_virtual_user_count => 1, 
                    :peak_virtual_user_count => 1, 
                    :delay_between_thread_start => 0,
                    :virtual_user_count_per_rampup => 1 }
    end
  end

  opts = default_opts.merge(opts)
  puts "[INFO] {LoadTestHelper} opts => #{opts.inspect}"
  start_virtual_user_count = opts[:start_virtual_user_count] || 2
  peak_virtual_user_count  = opts[:peak_virtual_user_count]  || 2
  delay_between_thread_start  =  opts[:delay_between_thread_start] || 0
  virtual_user_count_per_rampup = opts[:virtual_user_count_per_rampup] || 1
  
  for_how_long = opts[:for_how_long]
  
  # puts "DEBUG for_how_long => #{for_how_long}"
  if opts[:virtual_user_count] then
    start_virtual_user_count ||= opts[:virtual_user_count]
    peak_virtual_user_count ||= opts[:virtual_user_count]
  end
  
  raise "too many virtual users" if peak_virtual_user_count > MAX_VU
      
  if $LOADWISE_PREVIEW 
    start_virtual_user_count = peak_virtual_user_count = 1          
  end

  connect_to_loadwise("VU_START", "")
  all_start_time = Time.now

  if (peak_virtual_user_count <= 1)
    yield
  else
    threads = []
    vu_reports = {}
          
    start_virtual_user_count.times do |idx|          
      threads[idx] = Thread.new do
	Thread.current[:id] = idx + 1
        start_time = Time.now
        vu_reports[idx] ||= []
        begin
          if for_how_long 
            Timeout::timeout(for_how_long) do 
              while(true)
                yield
                Thread.pass
              end    
            end            
          else
            yield                  
          end
          
          vu_reports[idx] =  Thread.current[:log]
        rescue Timeout::Error                
          # Looping finished
          vu_reports[idx] = Thread.current[:log]                
        rescue => e
          vu_reports[idx] = Thread.current[:log] || []
          vu_reports[idx] ||= []
          vu_reports[idx] << { :error => e }
		# TODO
		connect_to_loadwise("VU_ERROR", Thread.current[:id].to_s + "|" + e.to_s)	              
		unless $vu_error_printed
			puts "VU[#{idx}] Failed: " +  e.backtrace.to_s
			$vu_error_printed = true
		end
	
        end
        vu_reports[idx] ||= []
        vu_reports[idx] << { :message => "Total Duration (Initial)", :start_time => start_time, :duration => Time.now - start_time }     
        connect_to_loadwise("VU_END", Thread.current[:id].to_s)
        # puts "VU[#{idx+1}] #{Time.now - start_time}s"
      end
    end

    (start_virtual_user_count..peak_virtual_user_count).step(virtual_user_count_per_rampup) do |nidx|
      sleep delay_between_thread_start
      virtual_user_count_per_rampup.times do |ridx|
        idx = nidx + ridx
        break if idx >= peak_virtual_user_count
        if idx == (peak_virtual_user_count - 1)
          connect_to_loadwise("VU_FULL", "#{Time.now}|#{Time.now - all_start_time}")      					
        end
	
        threads[idx] = Thread.new do
			Thread.current[:id] = idx + 1
          start_time = Time.now
          vu_reports[idx] ||= []
          begin
            if for_how_long 
              remaining_time = for_how_long - (Time.now - all_start_time)
              remaining_time = 1 if remaining_time < 0
              Timeout::timeout(remaining_time) do 
                while(true)
                  yield
                  Thread.pass                        
                end    
              end            
            else
              yield                  
            end
            vu_reports[idx] =  Thread.current[:log]
          rescue Timeout::Error
            # Looping finished
            vu_reports[idx] =  Thread.current[:log]
            # It is not error!!!
            # connect_to_loadwise("VU_ERROR", Thread.current[:id].to_s + "|" + "Timed out at #{Time.now.strftime('%H:%M:%S')} after #{for_how_long} s")
          rescue => e
            vu_reports[idx] =  Thread.current[:log] || []                
            vu_reports[idx] << { :error => e }
				connect_to_loadwise("VU_ERROR", Thread.current[:id].to_s + "|" + e.to_s)	              								
				unless $vu_error_printed
					puts "VU[#{idx}] Failed: " +  e.backtrace.to_s
					$vu_error_printed = true
				end
          end
          vu_reports[idx] ||= []
          vu_reports[idx] << { :message => "Total Duration (Peak)", :start_time => start_time,  :duration => Time.now - start_time }            
          puts "VU[#{idx+1}] #{Time.now - start_time}s"
        end          
      
      end #end of virtual user rampup
    end
    
    threads.each {|t| t.join; }
  
=begin
#
# No, LoadWise unable to see the database, also needs SQLite3 for Java
# 
# after test finishing, don't try to parse the data, LoadWise can see $memory database

    vu_reports.each do |key, value|
      value.each do |entry|
        append_test_result(key.to_s, entry[:file], entry[:message], entry[:start_time].to_i, entry[:duration])
        if entry[:error] then
          puts "{load_test_helper.rb} Execution Error: #{entry[:error]}"
         append_test_result(key.to_s, entry[:file], entry[:error], entry[:start_time].to_i, entry[:duration])
        else
          puts "[#{key}] #{entry[:message]}, #{entry[:duration]}"
        end
      end
    end
=end
    return vu_reports


  end
end

#symbol_to_sequence(symb) ⇒ Object

Convert :first to 1, :second to 2, and so on…



106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 106

def symbol_to_sequence(symb)
  value = { :zero => 0,
    :first => 1,
    :second => 2,
    :third => 3,
    :fourth => 4,
    :fifth => 5,
    :sixth => 6,
    :seventh => 7,
    :eighth => 8,
    :ninth => 9,
  :tenth => 10 }[symb]
  return value || symb.to_i
end

#try_for(timeout = $testwise_polling_timeout, polling_interval = $testwise_polling_interval || 1, &block) ⇒ Object Also known as: try_upto, try_until

Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds). Error will be ignored until timeout Example

try_for { click_link('waiting')}
try_for(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
try_for { click_button('Search' }


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/rwebspec-mechanize/load_test_helper.rb', line 84

def try_for(timeout = $testwise_polling_timeout, polling_interval = $testwise_polling_interval || 1, &block)
  start_time = Time.now

  last_error = nil
  until (duration = Time.now - start_time) > timeout
    begin
      return if yield
      last_error = nil
    rescue => e
      last_error = e
    end
    sleep polling_interval
  end

  raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
  raise "Timeout after #{duration.to_i} seconds."
end