For Dummies Stress Test Using JMeter in Rails 4 + Ruby 2.2

jmeter generated by ruby-jemer

Inspired by

  1. http://www.jetthoughts.com/blog/tricks/2014/08/05/stress-testing-your-rails-application-using-jmeter.html
  2. https://github.com/flood-io/ruby-jmeter
  3. http://jmeter.apache.org/usermanual/get-started.html

In your local machine (Mac OSX)

1
2
brew update
brew install jmeter --with-plugins

In your remote server

1
2
# if your want test in remote server
sudo apt-get install jmeter 

Gemfile

write test plans for JMeter easily

1
gem ruby-jmeter

寫Test Plan

[Rereference] 語法支援哪些:

  1. https://github.com/flood-io/ruby-jmeter/blob/5ae25cc32c8d05fcbe32bf143bdfbbd2d657517c/lib/ruby-jmeter/DSL.md

  2. 可查看 alies_methods https://github.com/flood-io/ruby-jmeter/blob/5ae25cc32c8d05fcbe32bf143bdfbbd2d657517c/lib/ruby-jmeter/dsl.rb

Write A Stress Test Helper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
# test/stress/stress_helper.rb

require 'ruby-jmeter'

def default_setting(params={})
  domain    = params[:domain]        || 'localhost' 
  protocol  = params[:protocol]      || 'https'
  port      = params[:port]          || '3000'
  cookie    = params[:cookie].to_s   || 'true'
  # defaults 會建立jmeter的 "HTTP Request Default",讓你設定 domain或是 protocol...等數值
  defaults domain: domain, protocol: protocol, port: port

  # cookies 會建立jmeter的 "HTTP Cookie Manager"
  # 如果希望每個threads都有自己的cookie,要將此行code,寫到thread內
  # cookies policy 之前卡了我很久,見註一
  cookies policy: 'compatibility',clear_each_iteration: true unless params[:cookie] == 'false'
end

# Login Helper 
# 因為我們登入後會倒回首頁,所以,我有檢查 使用者的名稱是否有出現
def login(email,pwd,nickname)
  visit name: 'Sign In', url: '/users/sign_in' do
    # 會抓變數,並且將值assign給 'csrf-token' 與 'csrf-param'
    extract name: 'csrf-token', xpath: "//meta[@name='csrf-token']/@content", tolerant: true
    extract name: 'csrf-param', xpath: "//meta[@name='csrf-param']/@content", tolerant: true
  end

  # For devise issue
  http_header_manager name: 'X-CSRF-Token', value: '${csrf-token}'

  # 送出登入
  submit name: 'Submit Sign In form', url: '/users/sign_in',
    always_encode: true,
    fill_in: {
      'utf8'          => '✓',
      '${csrf-param}' => '${csrf-token}',
      'user[email]'        => email,
      'user[password]'     => pwd,
      'commit'             => 'Log in'
    } do
    # 登入後會倒回首頁,檢查是否包含你的nickname
    assert contains: nickname, scope: 'main'
  end
end

註一: cookies policy 之前卡了我很久,因為我發現我登入都會錯誤!都是csrf-token 不相符,我的認知,那是因為Devise使用cookie作為判斷機制,所以cookie policy不能選用rfc2109,要選用compatibility 他會符合目前幾乎所有線上網站的cookie需求!

Ruby-Jmeter <-> Jmeter

ruby-jmeter-mapping-1

Non Login User Stress Test Plan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
53
54
55
56
57
58
59
60
61
62
63
# test/stress/non_login.rb

require './stress_helper' 
 
test do
  default_setting domain: 'your.awesome.website', portocal: 'https' , port: '443'
  #default_setting() # 本機測試使用
  
  # 壓測,登入後的行為
  # * 使用threads是因為 thread 代表jmeter裡面的thread_group,thread_group就是告訴jmeter
  #   有多少使用者要模擬,多久送一次requests,多少requests要被送出
  # * counts 代表 多少個使用者
  # * rampup 每個使用者的執行間隔
  # * loops 代表多重複做多少次測試
  
  for i in 1..10 
    threads count: 20, rampup: 1 ,loops: 1 do
      think_time 5000, 2000
        transaction "活動專區#{i}" do
          # 這邊會去爬 class: 'items' 底下每個 <a> 的href
        # 並且把他assign給 "act-urls"
          visit name: '活動專區首頁', url: "/activities?sort=1&page=#{Random.rand(1..4)}" do 
            extract name: 'act-urls', xpath: "//div[contains(@class,'items')]//a//@href", tolerant: true 
          end
          for i in 1..3
            visit name: "隨便點活動#{i}", url: "${act-urls_#{Random.rand(1..12)}}" do
              extract name: 'product-urls', xpath: "//div[contains(@class,'item-info')]//a//@href", tolerant: true 
            end
          end
        end
      view_results_tree
      debug_sampler
    end
  end 

  for i in 1..5
    threads count: 20, rampup: 1 ,loops: 1 do
      think_time 5000, 2000
        transaction "活動專區-標籤#{i}" do
          visit name: '活動專區首頁', url: "/activities" do 
            extract name: 'act-tag-urls', xpath: "//div[contains(@class,'keywords')]//a//@href", tolerant: true 
          end
          for i in 1..4
            visit name: "隨便點活動標籤#{i}", url: "${act-tag-urls_#{Random.rand(1..4)}}"
          end
        end
      view_results_tree
      debug_sampler
    end
  end 

  view_results_in_table
  graph_results
  aggregate_graph
  view_results_tree
  summary_report
 
end.run(
  gui: true,
  file: 'jmeter-visitor.jmx',
  log:  'jmeter-visitor.log',
  jtl:  'results-visit.jtl'
)

Ruby-Jmeter <-> Jmeter

ruby-jmeter-mapping-2

Login User Stress Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
# test/stress/login.rb 

require './stress_helper' 

test do
  default_setting domain: 'your.awesome.website', portocal: 'https' , port: '443'
  # default_setting() # 本機測試使用

  # 壓測,登入後的行為
  threads count: 10, rampup: 1, loops: 1 do
    think_time 5000, 2000
 
    transaction 'Log In and View page' do
 
     login('your@login.account','your-password','your-nickname')

    # 這邊會去爬 class: 'ucnh-fs-ls-uctrls' 底下每個 <a> 的href
    # 並且把他assign給 "users-urls"
      visit name: 'activity', url: '/activities' do 
        extract name: 'users-urls', xpath: "//div[contains(@class,'ucnh-fs-ls-uctrls')]//a//@href", tolerant: true 
      end
  
  # 因為users-urls是個 array,用法就是 ${users-url_X}, X代表array第X個element
      visit name: 'user list1', url: '${users-urls_1}'
      visit name: 'user lists2', url: '${users-urls_3}'
      visit name: 'user lists3', url: '${users-urls_4}'
      visit name: 'user profile', url: '${users-urls_5}'
      visit name: 'user account edit', url: '${users-urls_6}'
    end
    debug_sampler # 給Debug用
    view_results_tree
  end
  view_results_in_table
  graph_results
  aggregate_graph
  view_results_tree
  summary_report
 
end.run(
  gui: true,
  file: 'jmeter-after-sign-in.jmx',
  log:  'jmeter-after-sign-in.log',
  jtl:  'results-after-sign-in.jtl'
)

Ruby-Jmeter <-> Jmeter

ruby-jmeter-mapping-3-submit-form

開始測試

1
2
3
4
cd your_awesome_projects/test/stress
# ruby 你要執行的.rb檔,ex: 
ruby non_login.rb
# 此時會跳出一個apache jmeter的畫面,點選綠色執行按鈕即可

Others

Remove tracking jmeter generated files

1
2
echo "/test/stress/*.log" >> .gitignore
echo "/test/stress/*.jmx" >> .gitignore
Comments

Comments

Google Analytics Alternative