rails_api_benchmark 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|
-

|
14
|
-
{{/target}}
|
15
|
-
|
16
|
-
### Response
|
17
|
-
{{#results}}
|
18
|
-
```json
|
19
|
-
{{{response}}}
|
20
|
-
```
|
21
|
-
{{/results}}
|