rails_api_benchmark 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![{{title}}](../{{name}}_plot.jpg?raw=true "{{title}}")
|
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
|