rails_api_benchmark 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fc553c272bb5f42a3b765748336af37be9503e74
4
- data.tar.gz: 6cff65ef9d213d09b809fdc7d3b237a53707e824
3
+ metadata.gz: 11d43775977eaa602c80e9a4fe751dae26a0ba14
4
+ data.tar.gz: d134a38f1b2daaac6c8b2014cc2f50b81c93edab
5
5
  SHA512:
6
- metadata.gz: 144655c6afb4d8711864152918a5f78e6bbbdc0f2a5d56e61cd59fa62e205eb36c8b8453794a024903d0baf0df9a06acda0a5cd5fb05ffdae260951eec6f7f20
7
- data.tar.gz: faeda2140659f2f4d7a509c447ddde94813b770013b997963f1d91ef0651cfb90043f42fd301bc5c30d0960c3888450cb666e3c2cd5d260e8c48b7b2e46ee290
6
+ metadata.gz: 742f151da69b6eee0a0c93357dbccb4af28b03e770c2645685ca10852e15a635fc096f1e1f7b0b605e25382c54806d553c9bf954ed1d87e9964a4840b4bb59b3
7
+ data.tar.gz: 5b4dd39b9977699cbb638f912debf6f89281e7c26a8275f83eb9c29f28bc69e3401820942912b2934a6c1a6a8fe7b13ee3db87068503922ce907f991b344b95c
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2017 Doc
1
+ Copyright 2017 Terry Raimondo
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -27,7 +27,8 @@ Example output:
27
27
  "bench_cmd": "ab -n %{nb_requests} -c %{concurrency} -g plot.tsv -H \"%{auth_header}\" http://%{host}%{route}",
28
28
  "server_cmd": "bundle exec puma",
29
29
  "env_vars": {
30
- "RAILS_MAX_THREADS": "2"
30
+ "RAILS_MAX_THREADS": "2",
31
+ "RAILS_ENV": "production"
31
32
  },
32
33
  "regexps": [
33
34
  {
@@ -10,31 +10,37 @@ module RailsApiBenchmark
10
10
 
11
11
  def initialize
12
12
  @config = RailsApiBenchmark.config
13
+ @resultset = ResultSet.new
14
+ init_files
15
+ write_index
13
16
  end
14
17
 
15
18
  def run
16
- init_files
17
19
  @config.routes.each do |route|
18
20
  e = Endpoint.new(route)
19
21
  res = e.run_benchmark
20
- write_results(e, res)
22
+ @resultset.add(e, res)
21
23
  end
22
- create_index
24
+ @resultset.compute_relative_speed
25
+ write_results
23
26
  end
24
27
 
25
- def write_results(endpoint, results)
26
- Renderer.new(endpoint, results).process
28
+ private
29
+
30
+ def write_results
31
+ Views::SummaryMarkdown.new(@resultset).write if @config.summary
32
+
33
+ @resultset.each_result do |endpoint, results|
34
+ Renderer.new(endpoint, results).process
35
+ end
27
36
  end
28
37
 
29
38
  def init_files
30
39
  FileUtils.mkdir_p(@config.results_folder)
31
40
  end
32
41
 
33
- def create_index
34
- view = Views::IndexMarkdown.new(@config.routes)
35
- File.open(File.join(@config.results_folder, view.file_name), 'w') do |file|
36
- file << view.render
37
- end
42
+ def write_index
43
+ Views::IndexMarkdown.new.write
38
44
  end
39
45
  end
40
46
  end
@@ -1,11 +1,11 @@
1
1
  module RailsApiBenchmark
2
2
  module Logging
3
3
  class << self
4
+ attr_writer :logger
5
+
4
6
  def logger
5
7
  @logger ||= Logger.new(STDOUT)
6
8
  end
7
-
8
- attr_writer :logger
9
9
  end
10
10
 
11
11
  def self.included(base)
@@ -0,0 +1,48 @@
1
+ module RailsApiBenchmark
2
+ class ResultSet
3
+ attr_reader :results
4
+
5
+ def initialize
6
+ @results = []
7
+ end
8
+
9
+ def add(endpoint, results)
10
+ @results << { endpoint: endpoint, results: results }
11
+ end
12
+
13
+ def averages
14
+ rps = @results.map { |v| v[:results][:req_per_sec] }.compact
15
+ rt = @results.map { |v| v[:results][:response_time] }.compact
16
+
17
+ avg_rps = rps.inject(0) { |sum, v| sum + v.to_i } / rps.count
18
+ avg_rt = rt.inject(0) { |sum, v| sum + v.to_i } / rt.count
19
+
20
+ { req_per_sec: avg_rps, response_time: avg_rt }
21
+ end
22
+
23
+ # Returns only the results with the relative speed
24
+ def compute_relative_speed
25
+ @results = @results.map do |r|
26
+ avgs = averages
27
+ res = r[:results]
28
+
29
+ avg_rt = avgs[:response_time]
30
+ avg_rps = avgs[:req_per_sec]
31
+
32
+ f_rt = ((res[:response_time].to_f - avg_rt) / avg_rt * 100).round(1)
33
+ f_rps = ((res[:req_per_sec].to_f - avg_rps) / avg_rps * 100).round(1)
34
+ r.merge(factors: { response_time: f_rt, req_per_sec: f_rps })
35
+ end
36
+ end
37
+
38
+ # Use it like this:
39
+ # resultset.each_result do |endpoint, results|
40
+ # ...
41
+ # end
42
+ def each_result
43
+ @results.each do |r|
44
+ yield r[:endpoint], r[:results]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ # Benchmark
2
+
3
+ **Configuration:**
4
+ - Concurrency: <%= @config.concurrency %>
5
+ - Request nb: <%= @config.nb_requests %>
6
+ - Host: <%= @config.host %>
7
+
8
+ ## Endpoints tested (<%= @nb_routes -%>)
9
+
10
+ [See results summary](summary.md)
11
+
12
+ <% @routes.each do |r| -%>
13
+ ### <%= r[:title] %>
14
+ * Name: <%= r[:name] %>
15
+
16
+ * Route: <%= r[:route] %>
17
+
18
+ <% if r[:description] %>
19
+ * Description: <%= r[:description] %>
20
+ <% end %>
21
+
22
+ [See results](<%= r[:name] -%>/results.md)
23
+ <% end %>
@@ -0,0 +1,15 @@
1
+ # <%= @target.title %>
2
+
3
+ ### Results
4
+
5
+ Requests per second: <%= @results[:req_per_sec] %> #
6
+
7
+ Average response time: <%= @results[:response_time] %> ms
8
+
9
+ ### Graph
10
+ ![<%= @target.title %>](../<%= @target.name %>_plot.jpg?raw=true "<%= @target.title %>")
11
+
12
+ ### Response
13
+ ```json
14
+ <%= @results[:response] %>
15
+ ```
@@ -0,0 +1,19 @@
1
+ # Summary:
2
+
3
+ * Average response time: **<%= @avg[:response_time] -%> ms**
4
+ * Average requests per sec: **<%= @avg[:req_per_sec] -%> #**
5
+
6
+ |Route|Response time factor|Request per second factor|
7
+ |---|---|---|
8
+ <% @results.sort_by { |v| -v[:factors][:response_time] }.each do |r| -%>
9
+ <%
10
+ rps = r[:factors][:req_per_sec]
11
+ rt = r[:factors][:response_time]
12
+ -%>
13
+ <%# I don't care about magic string values, it's templating %>
14
+ <%=
15
+ "|#{r[:endpoint].title}" \
16
+ "|#{rt.abs} % #{rt < 0 ? 'faster than average' : 'slower than average'}" \
17
+ "|#{rps.abs} % #{rps >= 0 ? 'more than average' : 'less than average'}|\n"
18
+ -%>
19
+ <% end %>
@@ -1,3 +1,3 @@
1
1
  module RailsApiBenchmark
2
- VERSION = '0.2.2'.freeze
2
+ VERSION = '0.2.3'.freeze
3
3
  end
@@ -5,11 +5,10 @@ module RailsApiBenchmark
5
5
  class IndexMarkdown < View
6
6
  attr_reader :routes, :nb_routes, :config
7
7
 
8
- def initialize(routes)
8
+ def initialize
9
9
  super
10
10
  @file_name = 'README'
11
- @config = RailsApiBenchmark.config.all
12
- @routes = routes
11
+ @routes = @config.routes
13
12
  @nb_routes = routes.count
14
13
  end
15
14
 
@@ -0,0 +1,21 @@
1
+ require 'mustache'
2
+
3
+ module RailsApiBenchmark
4
+ module Views
5
+ class SummaryMarkdown < View
6
+ attr_reader :results, :avg
7
+
8
+ def initialize(resultset)
9
+ super
10
+ @file_name = 'summary'
11
+ @results = resultset.results
12
+ @avg = resultset.averages
13
+ end
14
+
15
+ # Maybe put this in a superclass like MarkdownView to DRY
16
+ def extension
17
+ 'md'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,22 +1,36 @@
1
- require 'mustache'
1
+ require 'erubis'
2
2
 
3
3
  module RailsApiBenchmark
4
4
  module Views
5
- class View < Mustache
5
+ class View
6
6
  def initialize(*_args)
7
+ @config = RailsApiBenchmark.config
7
8
  @template_path = File.expand_path('../../templates', __FILE__)
8
9
  end
9
10
 
11
+ # Override this method in your view
10
12
  def file_name
11
13
  "#{@file_name}.#{extension}"
12
14
  end
13
15
 
16
+ # Override this method in your view
17
+ def folder
18
+ nil
19
+ end
20
+
14
21
  def file_path
15
22
  [folder, file_name].compact.join('/')
16
23
  end
17
24
 
18
- def folder
19
- nil
25
+ def write
26
+ File.open(File.join(@config.results_folder, file_path), 'w') do |file|
27
+ file << render
28
+ end
29
+ end
30
+
31
+ def render
32
+ template = File.read(File.join(@template_path, "#{template_name}.erb"))
33
+ Erubis::Eruby.new(template).result(binding)
20
34
  end
21
35
 
22
36
  private
@@ -34,4 +48,5 @@ module RailsApiBenchmark
34
48
  end
35
49
 
36
50
  require_relative 'results_markdown'
51
+ require_relative 'summary_markdown'
37
52
  require_relative 'index_markdown'
@@ -3,6 +3,7 @@ require 'rails_api_benchmark/server'
3
3
  require 'rails_api_benchmark/core'
4
4
  require 'rails_api_benchmark/renderer'
5
5
  require 'rails_api_benchmark/graph'
6
+ require 'rails_api_benchmark/result_set'
6
7
  require 'rails_api_benchmark/subprocess'
7
8
  require 'rails_api_benchmark/endpoint'
8
9
  require 'rails_api_benchmark/views/view' # Requires all the views
@@ -11,7 +12,7 @@ module RailsApiBenchmark
11
12
  class Configuration
12
13
  attr_accessor :concurrency, :nb_requests, :auth_header,
13
14
  :server_cmd, :bench_cmd, :curl_cmd, :results_folder,
14
- :regexps, :env_vars, :routes, :host
15
+ :regexps, :env_vars, :routes, :host, :summary
15
16
 
16
17
  # Default values, INSANE. Must be refactored
17
18
  # Maybe create a yaml or json file to import for default values
@@ -23,6 +24,7 @@ module RailsApiBenchmark
23
24
  ' -H "%{auth_header}" http://%{host}%{route}'
24
25
  self.curl_cmd = 'curl -H "%{auth_header}" http://%{host}%{route}'
25
26
  self.results_folder = 'benchmark'
27
+ self.summary = true
26
28
  self.regexps = [
27
29
  {
28
30
  key: :response_time,
@@ -35,10 +37,11 @@ module RailsApiBenchmark
35
37
  }
36
38
  ]
37
39
  self.env_vars = {
38
- 'RAILS_MAX_THREADS' => 2,
39
- 'SSL_DISABLE' => true,
40
- 'SECRET_KEY_BASE' => '123',
41
- 'PORT' => 5000
40
+ 'RAILS_MAX_THREADS' => '2',
41
+ 'RAILS_ENV' => 'production',
42
+ 'SSL_DISABLE' => 'true',
43
+ 'SECRET_KEY_BASE' => 'a1b2c3',
44
+ 'PORT' => '5000'
42
45
  }
43
46
  self.routes = []
44
47
  self.host = 'localhost:5000'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_api_benchmark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Terry Raimondo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-13 00:00:00.000000000 Z
11
+ date: 2017-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -25,25 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.1.2
27
27
  - !ruby/object:Gem::Dependency
28
- name: mustache
28
+ name: erubis
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.0'
34
31
  - - ">="
35
32
  - !ruby/object:Gem::Version
36
- version: 0.99.4
33
+ version: '0'
37
34
  type: :runtime
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
40
37
  requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '1.0'
44
38
  - - ">="
45
39
  - !ruby/object:Gem::Version
46
- version: 0.99.4
40
+ version: '0'
47
41
  description: Benchmark your API endpoints and get the results fast ! This gem leverages
48
42
  the power of ApacheBench, but can be configured with another benchmark tool
49
43
  email:
@@ -65,14 +59,16 @@ files:
65
59
  - lib/rails_api_benchmark/graph.rb
66
60
  - lib/rails_api_benchmark/logging.rb
67
61
  - lib/rails_api_benchmark/renderer.rb
68
- - lib/rails_api_benchmark/results_markdown.rb
62
+ - lib/rails_api_benchmark/result_set.rb
69
63
  - lib/rails_api_benchmark/server.rb
70
64
  - lib/rails_api_benchmark/subprocess.rb
71
- - lib/rails_api_benchmark/templates/index_markdown.mustache
72
- - lib/rails_api_benchmark/templates/results_markdown.mustache
65
+ - lib/rails_api_benchmark/templates/index_markdown.erb
66
+ - lib/rails_api_benchmark/templates/results_markdown.erb
67
+ - lib/rails_api_benchmark/templates/summary_markdown.erb
73
68
  - lib/rails_api_benchmark/version.rb
74
69
  - lib/rails_api_benchmark/views/index_markdown.rb
75
70
  - lib/rails_api_benchmark/views/results_markdown.rb
71
+ - lib/rails_api_benchmark/views/summary_markdown.rb
76
72
  - lib/rails_api_benchmark/views/view.rb
77
73
  homepage: https://github.com/terry90/rails_api_benchmark
78
74
  licenses:
@@ -1,29 +0,0 @@
1
- require 'mustache'
2
-
3
- module RailsApiBenchmark
4
- module Views
5
- class ResultsMarkdown < View
6
- attr_reader :title, :req_per_sec, :response_time
7
-
8
- def initialize(target, results)
9
- super
10
- @title = target.title
11
- @req_per_sec = results[:req_per_sec] || 'Unknown'
12
- @response_time = results[:response_time] || 'Unknown'
13
- end
14
-
15
- # Maybe put this in a superclass like MarkdownView to DRY
16
- def extension
17
- 'md'
18
- end
19
-
20
- def file_name
21
- 'results'
22
- end
23
-
24
- def folder
25
- @target.name
26
- end
27
- end
28
- end
29
- end
@@ -1,26 +0,0 @@
1
- # Benchmark results:
2
-
3
- {{#config}}
4
- **Configuration:**
5
- - Concurrency: {{concurrency}}
6
- - Request nb: {{nb_requests}}
7
- - Host: {{host}}
8
- {{/config}}
9
-
10
- ## Endpoints tested ({{nb_routes}})
11
-
12
- {{#routes}}
13
- {{#.}}
14
- ### {{title}}
15
- * Name: {{name}}
16
-
17
- * Route: {{route}}
18
-
19
- {{#description}}
20
- * Description: {{description}}
21
- {{/description}}
22
-
23
- [See results]({{name}}/results.md)
24
-
25
- {{/.}}
26
- {{/routes}}
@@ -1,21 +0,0 @@
1
- # {{title}}
2
-
3
- ### Results
4
-
5
- {{#results}}
6
- Requests per second: {{req_per_sec}} #
7
-
8
- Average response time: {{response_time}} ms
9
- {{/results}}
10
-
11
- {{#target}}
12
- ### Graph
13
- ![{{title}}](../{{name}}_plot.jpg?raw=true "{{title}}")
14
- {{/target}}
15
-
16
- ### Response
17
- {{#results}}
18
- ```json
19
- {{{response}}}
20
- ```
21
- {{/results}}