rails_api_benchmark 0.1.1 → 0.2.0
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/README.md +8 -2
- data/lib/rails_api_benchmark/benchmark_tasks.rb +2 -1
- data/lib/rails_api_benchmark/core.rb +30 -9
- data/lib/rails_api_benchmark/endpoint.rb +11 -4
- data/lib/rails_api_benchmark/graph.rb +23 -0
- data/lib/rails_api_benchmark/logging.rb +0 -13
- data/lib/rails_api_benchmark/renderer.rb +27 -0
- data/lib/rails_api_benchmark/results_markdown.rb +29 -0
- data/lib/rails_api_benchmark/templates/index_markdown.mustache +26 -0
- data/lib/rails_api_benchmark/templates/results_markdown.mustache +21 -0
- data/lib/rails_api_benchmark/version.rb +1 -1
- data/lib/rails_api_benchmark/views/index_markdown.rb +22 -0
- data/lib/rails_api_benchmark/views/results_markdown.rb +25 -0
- data/lib/rails_api_benchmark/views/view.rb +37 -0
- data/lib/rails_api_benchmark.rb +3 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a90d0eb56db8b3b59f332bddfc6922a04d665bf0
|
4
|
+
data.tar.gz: 5da05eee4add84cc3ad4de8121cdbfaf912a1a14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02d6a923a95a529fcc83552f5e40b6988cb2b22449ee964af315bd867e69c45521e43d146a3251f54d4d623fdf84d6670272956ec2d83d8c346ea1ffd8b9de9d
|
7
|
+
data.tar.gz: 0fda977c19ab3012a0b2ba4a47c1a3d3f5a96e72770a5e17a1c2e567b345416da3b30d5dbb05dfc05a238499bb5fb2b3232e21c9e46dd265616ba3f6e2f3e7fe
|
data/README.md
CHANGED
@@ -6,6 +6,12 @@ Work in progress, yet you can use it like this.
|
|
6
6
|
|
7
7
|
Run it with rake api:benchmark
|
8
8
|
|
9
|
+
## Important
|
10
|
+
|
11
|
+
* Only JSON responses are supported yet
|
12
|
+
* Only GET requests are supported yet
|
13
|
+
* Configuration is not validated
|
14
|
+
|
9
15
|
## Installation
|
10
16
|
|
11
17
|
Install gnuplot (Google)
|
@@ -47,9 +53,11 @@ unless Rails.env.production?
|
|
47
53
|
}
|
48
54
|
config.regexps = [ # Used to get results from the output of benchmark tools
|
49
55
|
{
|
56
|
+
key: :response_time,
|
50
57
|
name: 'Average time per request (ms)',
|
51
58
|
regexp: /Time\s+per\s+request:\s+([0-9.]*).*\(mean\)/
|
52
59
|
}, {
|
60
|
+
key: :req_per_sec,
|
53
61
|
name: 'Requests per second (#)',
|
54
62
|
regexp: /Requests\s+per\s+second:\s+([0-9.]*).*\(mean\)/
|
55
63
|
}
|
@@ -82,8 +90,6 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
82
90
|
|
83
91
|
### TODO
|
84
92
|
* POST requests
|
85
|
-
* Create Formatter class to avoid dirty code in Endpoint
|
86
|
-
* Create markdown template to embed nicely on github (Mustache)
|
87
93
|
* Create generators (for config initializer first)
|
88
94
|
* Add simplecov to permit controller coverage for example
|
89
95
|
* Generate documentation page(s) (markdown) to list the results
|
@@ -4,15 +4,36 @@ module RailsApiBenchmark
|
|
4
4
|
class Core
|
5
5
|
include Logging
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
def self.run
|
8
|
+
new.run
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@config = RailsApiBenchmark.config
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
init_files
|
17
|
+
@config.routes.each do |route|
|
18
|
+
e = Endpoint.new(route)
|
19
|
+
res = e.run_benchmark
|
20
|
+
write_results(e, res)
|
21
|
+
end
|
22
|
+
create_index
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_results(endpoint, results)
|
26
|
+
Renderer.new(endpoint, results).process
|
27
|
+
end
|
28
|
+
|
29
|
+
def init_files
|
30
|
+
FileUtils.mkdir_p(@config.results_folder)
|
31
|
+
end
|
32
|
+
|
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
|
16
37
|
end
|
17
38
|
end
|
18
39
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'json'
|
4
|
+
|
3
5
|
module RailsApiBenchmark
|
4
6
|
class Endpoint
|
5
7
|
include Logging
|
@@ -11,11 +13,16 @@ module RailsApiBenchmark
|
|
11
13
|
@route = opts[:route]
|
12
14
|
@method = opts[:method]
|
13
15
|
@title = opts[:title]
|
14
|
-
@
|
15
|
-
@results = []
|
16
|
+
@results = {}
|
16
17
|
@results_folder = "#{RailsApiBenchmark.config.results_folder}/#{@name}"
|
17
18
|
end
|
18
19
|
|
20
|
+
def run_benchmark
|
21
|
+
query
|
22
|
+
benchmark
|
23
|
+
@results
|
24
|
+
end
|
25
|
+
|
19
26
|
def benchmark
|
20
27
|
benchmark_cmd = RailsApiBenchmark.config.bench_cmd
|
21
28
|
opts = RailsApiBenchmark.config.all.merge(route: @route)
|
@@ -23,14 +30,14 @@ module RailsApiBenchmark
|
|
23
30
|
output = `#{benchmark_cmd % opts}`
|
24
31
|
|
25
32
|
regexps = RailsApiBenchmark.config.regexps
|
26
|
-
regexps.each { |r| @results
|
33
|
+
regexps.each { |r| @results[r[:key]] = output.scan(r[:regexp]).flatten.first }
|
27
34
|
end
|
28
35
|
|
29
36
|
def query
|
30
37
|
curl_cmd = RailsApiBenchmark.config.curl_cmd
|
31
38
|
opts = RailsApiBenchmark.config.all.merge(route: @route)
|
32
39
|
|
33
|
-
@response = `#{curl_cmd % opts}`
|
40
|
+
@results[:response] = JSON.pretty_generate(JSON.parse(`#{curl_cmd % opts}`))
|
34
41
|
end
|
35
42
|
|
36
43
|
private
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RailsApiBenchmark
|
2
|
+
class Graph
|
3
|
+
def initialize(target, output_dir)
|
4
|
+
@output_dir = output_dir
|
5
|
+
@target = target
|
6
|
+
end
|
7
|
+
|
8
|
+
def generate
|
9
|
+
run
|
10
|
+
copy_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
gnuplotscript = File.expand_path('../../../gnuplotscript', __FILE__)
|
15
|
+
`gnuplot -e "plot_title='Benchmark #{@target.title}'; plot_file='#{@target.name}_plot.jpg'" #{gnuplotscript}`
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy_file
|
19
|
+
dest = File.join(@output_dir)
|
20
|
+
FileUtils.mv("#{@target.name}_plot.jpg", dest)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,15 +1,3 @@
|
|
1
|
-
# module RailsApiBenchmark
|
2
|
-
# module Logging
|
3
|
-
# def logger
|
4
|
-
# Logging.logger
|
5
|
-
# end
|
6
|
-
#
|
7
|
-
# def self.logger
|
8
|
-
# @logger ||= Logger.new(STDOUT)
|
9
|
-
# end
|
10
|
-
# end
|
11
|
-
# end
|
12
|
-
|
13
1
|
module RailsApiBenchmark
|
14
2
|
module Logging
|
15
3
|
class << self
|
@@ -20,7 +8,6 @@ module RailsApiBenchmark
|
|
20
8
|
attr_writer :logger
|
21
9
|
end
|
22
10
|
|
23
|
-
# Addition
|
24
11
|
def self.included(base)
|
25
12
|
class << base
|
26
13
|
def logger
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RailsApiBenchmark
|
2
|
+
class Renderer
|
3
|
+
attr_reader :output_dir, :target, :results
|
4
|
+
|
5
|
+
def initialize(target, results)
|
6
|
+
@output_dir = RailsApiBenchmark.config.results_folder
|
7
|
+
@target = target
|
8
|
+
@results = results
|
9
|
+
end
|
10
|
+
|
11
|
+
def process
|
12
|
+
Graph.new(@target, @output_dir).generate
|
13
|
+
generate_view
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def generate_view
|
19
|
+
view = Views::ResultsMarkdown.new(target, results)
|
20
|
+
dest = File.join(@output_dir, view.file_path)
|
21
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
22
|
+
File.open(File.join(@output_dir, view.file_path), 'w') do |file|
|
23
|
+
file << view.render
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
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}}
|
@@ -0,0 +1,21 @@
|
|
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}}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module RailsApiBenchmark
|
4
|
+
module Views
|
5
|
+
class IndexMarkdown < View
|
6
|
+
attr_reader :routes, :nb_routes, :config
|
7
|
+
|
8
|
+
def initialize(routes)
|
9
|
+
super
|
10
|
+
@file_name = 'README'
|
11
|
+
@config = RailsApiBenchmark.config.all
|
12
|
+
@routes = routes
|
13
|
+
@nb_routes = routes.count
|
14
|
+
end
|
15
|
+
|
16
|
+
# Maybe put this in a superclass like MarkdownView to DRY
|
17
|
+
def extension
|
18
|
+
'md'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module RailsApiBenchmark
|
4
|
+
module Views
|
5
|
+
class ResultsMarkdown < View
|
6
|
+
attr_reader :title, :results, :target
|
7
|
+
|
8
|
+
def initialize(target, results)
|
9
|
+
super
|
10
|
+
@file_name = 'results'
|
11
|
+
@target = target
|
12
|
+
@results = results
|
13
|
+
end
|
14
|
+
|
15
|
+
# Maybe put this in a superclass like MarkdownView to DRY
|
16
|
+
def extension
|
17
|
+
'md'
|
18
|
+
end
|
19
|
+
|
20
|
+
def folder
|
21
|
+
@target.name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module RailsApiBenchmark
|
4
|
+
module Views
|
5
|
+
class View < Mustache
|
6
|
+
def initialize(*_args)
|
7
|
+
@template_path = File.expand_path('../../templates', __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def file_name
|
11
|
+
"#{@file_name}.#{extension}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_path
|
15
|
+
[folder, file_name].compact.join('/')
|
16
|
+
end
|
17
|
+
|
18
|
+
def folder
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def template_name # Avoid module
|
25
|
+
self.class.name
|
26
|
+
.split('::').last
|
27
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
28
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
29
|
+
.tr('-', '_')
|
30
|
+
.downcase
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
require_relative 'results_markdown'
|
37
|
+
require_relative 'index_markdown'
|
data/lib/rails_api_benchmark.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'rails_api_benchmark/logging'
|
2
2
|
require 'rails_api_benchmark/server'
|
3
3
|
require 'rails_api_benchmark/core'
|
4
|
+
require 'rails_api_benchmark/renderer'
|
5
|
+
require 'rails_api_benchmark/graph'
|
4
6
|
require 'rails_api_benchmark/subprocess'
|
5
7
|
require 'rails_api_benchmark/endpoint'
|
8
|
+
require 'rails_api_benchmark/views/view' # Requires all the views
|
6
9
|
|
7
10
|
module RailsApiBenchmark
|
8
11
|
class Config
|
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.
|
4
|
+
version: 0.2.0
|
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-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -59,10 +59,18 @@ files:
|
|
59
59
|
- lib/rails_api_benchmark/benchmark_tasks.rb
|
60
60
|
- lib/rails_api_benchmark/core.rb
|
61
61
|
- lib/rails_api_benchmark/endpoint.rb
|
62
|
+
- lib/rails_api_benchmark/graph.rb
|
62
63
|
- lib/rails_api_benchmark/logging.rb
|
64
|
+
- lib/rails_api_benchmark/renderer.rb
|
65
|
+
- lib/rails_api_benchmark/results_markdown.rb
|
63
66
|
- lib/rails_api_benchmark/server.rb
|
64
67
|
- lib/rails_api_benchmark/subprocess.rb
|
68
|
+
- lib/rails_api_benchmark/templates/index_markdown.mustache
|
69
|
+
- lib/rails_api_benchmark/templates/results_markdown.mustache
|
65
70
|
- lib/rails_api_benchmark/version.rb
|
71
|
+
- lib/rails_api_benchmark/views/index_markdown.rb
|
72
|
+
- lib/rails_api_benchmark/views/results_markdown.rb
|
73
|
+
- lib/rails_api_benchmark/views/view.rb
|
66
74
|
homepage: https://github.com/terry90/rails_api_benchmark
|
67
75
|
licenses:
|
68
76
|
- MIT
|