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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +2 -1
- data/lib/rails_api_benchmark/core.rb +16 -10
- data/lib/rails_api_benchmark/logging.rb +2 -2
- data/lib/rails_api_benchmark/result_set.rb +48 -0
- data/lib/rails_api_benchmark/templates/index_markdown.erb +23 -0
- data/lib/rails_api_benchmark/templates/results_markdown.erb +15 -0
- data/lib/rails_api_benchmark/templates/summary_markdown.erb +19 -0
- data/lib/rails_api_benchmark/version.rb +1 -1
- data/lib/rails_api_benchmark/views/index_markdown.rb +2 -3
- data/lib/rails_api_benchmark/views/summary_markdown.rb +21 -0
- data/lib/rails_api_benchmark/views/view.rb +19 -4
- data/lib/rails_api_benchmark.rb +8 -5
- metadata +10 -14
- data/lib/rails_api_benchmark/results_markdown.rb +0 -29
- data/lib/rails_api_benchmark/templates/index_markdown.mustache +0 -26
- data/lib/rails_api_benchmark/templates/results_markdown.mustache +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11d43775977eaa602c80e9a4fe751dae26a0ba14
|
4
|
+
data.tar.gz: d134a38f1b2daaac6c8b2014cc2f50b81c93edab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 742f151da69b6eee0a0c93357dbccb4af28b03e770c2645685ca10852e15a635fc096f1e1f7b0b605e25382c54806d553c9bf954ed1d87e9964a4840b4bb59b3
|
7
|
+
data.tar.gz: 5b4dd39b9977699cbb638f912debf6f89281e7c26a8275f83eb9c29f28bc69e3401820942912b2934a6c1a6a8fe7b13ee3db87068503922ce907f991b344b95c
|
data/MIT-LICENSE
CHANGED
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
|
-
|
22
|
+
@resultset.add(e, res)
|
21
23
|
end
|
22
|
-
|
24
|
+
@resultset.compute_relative_speed
|
25
|
+
write_results
|
23
26
|
end
|
24
27
|
|
25
|
-
|
26
|
-
|
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
|
34
|
-
|
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
|
@@ -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 %>
|
@@ -5,11 +5,10 @@ module RailsApiBenchmark
|
|
5
5
|
class IndexMarkdown < View
|
6
6
|
attr_reader :routes, :nb_routes, :config
|
7
7
|
|
8
|
-
def initialize
|
8
|
+
def initialize
|
9
9
|
super
|
10
10
|
@file_name = 'README'
|
11
|
-
@
|
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 '
|
1
|
+
require 'erubis'
|
2
2
|
|
3
3
|
module RailsApiBenchmark
|
4
4
|
module Views
|
5
|
-
class View
|
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
|
19
|
-
|
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'
|
data/lib/rails_api_benchmark.rb
CHANGED
@@ -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
|
-
'
|
40
|
-
'
|
41
|
-
'
|
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.
|
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-
|
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:
|
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
|
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
|
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/
|
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.
|
72
|
-
- lib/rails_api_benchmark/templates/results_markdown.
|
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}}
|