kametori 0.0.2 → 0.0.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.
- data/.rspec +2 -0
- data/README.md +21 -2
- data/kametori.gemspec +2 -0
- data/lib/kametori/version.rb +1 -1
- data/lib/kametori.rb +72 -19
- data/spec/kametori_spec.rb +152 -0
- data/spec/spec_helper.rb +14 -0
- metadata +39 -2
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Kametori
|
2
2
|
|
3
|
-
|
3
|
+
Kametori helps you to write a benchmark test suite
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,26 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
The best way to use this gem is adding a profile to your
|
22
|
+
cucumber.yml file (usually located in config in Rails projects).
|
23
|
+
Like:
|
24
|
+
benchmark: --format progress -r features/support/benchmark.rb
|
25
|
+
|
26
|
+
And in features/support/benchmark.rb you write:
|
27
|
+
|
28
|
+
Kametori.scenario_limits = [{ tag: "fast_scenario", limit:1 },
|
29
|
+
{tag:"slow_scenario", limit:10}]
|
30
|
+
|
31
|
+
Kametori.raise_errors = true
|
32
|
+
|
33
|
+
Around do |scenario, block|
|
34
|
+
Kametori.scenario_benchmark(scenario) do
|
35
|
+
block.call
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
22
41
|
|
23
42
|
## Contributing
|
24
43
|
|
data/kametori.gemspec
CHANGED
data/lib/kametori/version.rb
CHANGED
data/lib/kametori.rb
CHANGED
@@ -2,36 +2,89 @@ require "kametori/version"
|
|
2
2
|
|
3
3
|
module Kametori
|
4
4
|
# exception classes
|
5
|
-
class
|
6
|
-
end
|
7
|
-
class Timeout < RuntimeError
|
8
|
-
|
5
|
+
class Timeout < StandardError
|
9
6
|
end
|
10
7
|
|
11
8
|
class << self
|
12
|
-
|
13
|
-
|
9
|
+
attr_accessor :raise_errors
|
10
|
+
def reset!
|
11
|
+
@raise_errors = false
|
12
|
+
@limits = []
|
13
|
+
@repeat_count = 1
|
14
|
+
end
|
15
|
+
def scenario_limits=(limits)
|
16
|
+
check_limits (limits)
|
14
17
|
@limits = limits
|
15
18
|
end
|
16
19
|
|
17
|
-
def
|
18
|
-
@limits
|
20
|
+
def scenario_limits
|
21
|
+
@limits || []
|
22
|
+
end
|
23
|
+
|
24
|
+
def average_over=(count)
|
25
|
+
raise( ArgumentError, "Wrong average over count") unless count.is_a? Integer
|
26
|
+
raise( ArgumentError, "Wrong average over count") if count < 1
|
27
|
+
@repeat_count = count
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_scenario
|
31
|
+
@current_scenario || {}
|
19
32
|
end
|
20
33
|
|
21
|
-
def
|
22
|
-
|
34
|
+
def average_over
|
35
|
+
current_scenario[:average_over] || @repeat_count || 1
|
36
|
+
end
|
37
|
+
|
38
|
+
def scenario_benchmark(scenario, options={}, &block)
|
39
|
+
under_test = find_scenario_under_test(scenario)
|
23
40
|
return nil if under_test.nil?
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
if ( elapsed > under_test[:limit])
|
30
|
-
raise Timeout
|
31
|
-
end
|
32
|
-
end
|
41
|
+
return nil unless block_given?
|
42
|
+
|
43
|
+
elapsed = execute_with_timing(average_over) { block.call }
|
44
|
+
limit = under_test[:limit]
|
45
|
+
check_finish_on_time(elapsed,limit)
|
33
46
|
elapsed
|
34
47
|
end
|
35
48
|
|
49
|
+
private
|
50
|
+
|
51
|
+
def check_limits(limits)
|
52
|
+
correct = limits.is_a?(Array) &&
|
53
|
+
limits.all? { |l| l.include?(:tag) && l.include?(:limit) && l[:limit].is_a?(Numeric)}
|
54
|
+
raise( ArgumentError, "wrong scenario limits") unless correct
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_scenario_under_test(scenario)
|
58
|
+
@current_scenario = @limits.find{ |limit| scenario.source_tag_names.include? limit[:tag] }
|
59
|
+
end
|
60
|
+
|
61
|
+
def execute_with_timing(average_over)
|
62
|
+
elapsed = []
|
63
|
+
average_over.times do
|
64
|
+
before = Time.now
|
65
|
+
yield
|
66
|
+
after = Time.now
|
67
|
+
elapsed.push (after - before)
|
68
|
+
end
|
69
|
+
mean(elapsed)
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_finish_on_time( elapsed, limit )
|
73
|
+
if raise_errors
|
74
|
+
if ( elapsed > limit)
|
75
|
+
raise Timeout, "Scenario timed out with #{format_float(elapsed)} > #{limit}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def format_float(float)
|
81
|
+
"%.3f" % float
|
82
|
+
end
|
83
|
+
|
84
|
+
def mean(array)
|
85
|
+
sum = array.inject(0){ |accum, i| accum + i }
|
86
|
+
sum / array.length.to_f
|
87
|
+
end
|
88
|
+
|
36
89
|
end
|
37
90
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# our mock for a cucumber scenario
|
4
|
+
class Scenario
|
5
|
+
attr_accessor :source_tag_names
|
6
|
+
attr_accessor :execution_time
|
7
|
+
attr_reader :times_called
|
8
|
+
def initialize (names)
|
9
|
+
@source_tag_names = [*names]
|
10
|
+
@execution_time = 0.1
|
11
|
+
@times_called = 0
|
12
|
+
end
|
13
|
+
def execute
|
14
|
+
Timecop.travel Time.now + @execution_time
|
15
|
+
@times_called += 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Kametori do
|
20
|
+
|
21
|
+
=begin
|
22
|
+
describe '.standard=' do
|
23
|
+
it 'raises Kametori::Error if is an unknown standard' do
|
24
|
+
expect {Kametori.standard='asdfasdf'}.to raise_error(Kamitori::Error)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.speed_test' do
|
29
|
+
end
|
30
|
+
=end
|
31
|
+
describe '.scenario_limits=' do
|
32
|
+
it 'should raise an error if the param is not an array' do
|
33
|
+
expect { Kametori.scenario_limits= 2 }.to raise_error(ArgumentError, "wrong scenario limits")
|
34
|
+
end
|
35
|
+
it 'should raise an error if there is no limit for tag' do
|
36
|
+
expect { Kametori.scenario_limits=[{tag:"aa"}] }.to raise_error(ArgumentError, "wrong scenario limits")
|
37
|
+
end
|
38
|
+
it 'should raise and error if there is no tag for limit' do
|
39
|
+
expect { Kametori.scenario_limits=[{limit:2}] }.to raise_error(ArgumentError, "wrong scenario limits")
|
40
|
+
end
|
41
|
+
it 'should raise and error if limit is not numeric' do
|
42
|
+
limits = [{ tag: "A", limit: "a"} ]
|
43
|
+
expect { Kametori.scenario_limits= limits }.to raise_error(ArgumentError, "wrong scenario limits")
|
44
|
+
end
|
45
|
+
it 'should set the limits for the tags' do
|
46
|
+
limits = [{ tag: "A", limit: 1} ]
|
47
|
+
Kametori.scenario_limits = limits
|
48
|
+
Kametori.scenario_limits.should == limits
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '.reset!' do
|
53
|
+
it 'should reset to the defaults' do
|
54
|
+
Kametori.reset!
|
55
|
+
Kametori.average_over.should == 1
|
56
|
+
Kametori.scenario_limits.should be_empty
|
57
|
+
Kametori.raise_errors.should be_false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
describe '.average_over' do
|
61
|
+
it 'should raise an error if the parameter is not integer' do
|
62
|
+
expect { Kametori.average_over=1.2 }.to raise_error(ArgumentError, "Wrong average over count")
|
63
|
+
end
|
64
|
+
it 'should raise an error if the parameter is less than 1' do
|
65
|
+
expect { Kametori.average_over=0 }.to raise_error(ArgumentError, "Wrong average over count")
|
66
|
+
end
|
67
|
+
it 'defaults to 1 executions' do
|
68
|
+
Kametori.average_over.should == 1
|
69
|
+
Kametori.average_over= 10
|
70
|
+
Kametori.average_over.should == 10
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '.scenario_benchmark' do
|
75
|
+
before do
|
76
|
+
@time_limit = 0.2
|
77
|
+
Timecop.freeze Time.now
|
78
|
+
limits = [{ tag: "MyTag", limit: @time_limit}, {tag: "MyTag2", limit:@time_limit} ]
|
79
|
+
Kametori.scenario_limits = limits
|
80
|
+
Kametori.average_over= 1
|
81
|
+
end
|
82
|
+
it 'should return nil if we do not have a limit for this scenario' do
|
83
|
+
scenario = Scenario.new("OtherTag")
|
84
|
+
Kametori.scenario_benchmark( scenario ) do
|
85
|
+
scenario.execute
|
86
|
+
end.should == nil
|
87
|
+
end
|
88
|
+
it 'should return nil if no block given' do
|
89
|
+
scenario = Scenario.new("MyTag")
|
90
|
+
Kametori.scenario_benchmark( scenario ).should == nil
|
91
|
+
end
|
92
|
+
it 'should return the time it took to finish the scenario' do
|
93
|
+
scenario = Scenario.new("MyTag")
|
94
|
+
Kametori.scenario_benchmark( scenario ) do
|
95
|
+
scenario.execute
|
96
|
+
end.should >= 0.1
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should work with scenarios with several tags' do
|
100
|
+
scenario = Scenario.new(["MyTag", "otherTag", "one_more"])
|
101
|
+
Kametori.scenario_benchmark( scenario ) do
|
102
|
+
scenario.execute
|
103
|
+
end.should >= 0.1
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '.average_over' do
|
107
|
+
it 'should call average_over times the block passed' do
|
108
|
+
scenario = Scenario.new("MyTag")
|
109
|
+
Kametori.average_over = 5
|
110
|
+
Kametori.scenario_benchmark( scenario ) do
|
111
|
+
scenario.execute
|
112
|
+
end
|
113
|
+
scenario.times_called.should == 5
|
114
|
+
Kametori.average_over = 1
|
115
|
+
end
|
116
|
+
it '.average_over can be overriden by the value in the hash' do
|
117
|
+
old_limits = Kametori.scenario_limits
|
118
|
+
limits = [{ tag: "MyTag", limit: @time_limit, average_over: 2}, {tag: "MyTag2", limit:@time_limit} ]
|
119
|
+
Kametori.scenario_limits = limits
|
120
|
+
Kametori.average_over = 5
|
121
|
+
scenario = Scenario.new("MyTag")
|
122
|
+
Kametori.scenario_benchmark( scenario ) do
|
123
|
+
scenario.execute
|
124
|
+
end
|
125
|
+
scenario.times_called.should == 2
|
126
|
+
Kametori.scenario_limits = old_limits
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '.raise_errors' do
|
131
|
+
it 'should return the time it took to finish the scenario and not raise if it finished before the limit' do
|
132
|
+
scenario = Scenario.new("MyTag")
|
133
|
+
Kametori.raise_errors = true
|
134
|
+
Kametori.scenario_benchmark( scenario ) do
|
135
|
+
scenario.execute
|
136
|
+
end.should < 0.2
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should raise Kametori::Timeout if the scenario is slower than its limit and we set to raise' do
|
140
|
+
scenario = Scenario.new("MyTag")
|
141
|
+
scenario.execution_time = 0.21
|
142
|
+
Kametori.raise_errors = true
|
143
|
+
expect do
|
144
|
+
Kametori.scenario_benchmark( scenario ) do
|
145
|
+
scenario.execute
|
146
|
+
end
|
147
|
+
end.to raise_error( Kametori::Timeout, /Scenario timed out with [0-9]*\.?[0-9]{3} > #{@time_limit}/ )
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../lib/kametori'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
6
|
+
config.run_all_when_everything_filtered = true
|
7
|
+
config.filter_run :focus
|
8
|
+
|
9
|
+
# Run specs in random order to surface order dependencies. If you find an
|
10
|
+
# order dependency and want to debug it, you can fix the order by providing
|
11
|
+
# the seed, which is printed after each run.
|
12
|
+
# --seed 1234
|
13
|
+
config.order = 'random'
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kametori
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,6 +27,38 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 2.2.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: timecop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: debugger
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
30
62
|
description: A gem to create benchmark suites for your app. It allows you to keep
|
31
63
|
track of your performance
|
32
64
|
email:
|
@@ -36,6 +68,7 @@ extensions: []
|
|
36
68
|
extra_rdoc_files: []
|
37
69
|
files:
|
38
70
|
- .gitignore
|
71
|
+
- .rspec
|
39
72
|
- Gemfile
|
40
73
|
- LICENSE
|
41
74
|
- README.md
|
@@ -43,6 +76,8 @@ files:
|
|
43
76
|
- kametori.gemspec
|
44
77
|
- lib/kametori.rb
|
45
78
|
- lib/kametori/version.rb
|
79
|
+
- spec/kametori_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
46
81
|
homepage: http://www.github.com/JordiPolo/kametori
|
47
82
|
licenses: []
|
48
83
|
post_install_message:
|
@@ -67,5 +102,7 @@ rubygems_version: 1.8.24
|
|
67
102
|
signing_key:
|
68
103
|
specification_version: 3
|
69
104
|
summary: A gem to create benchmark suites for your app.
|
70
|
-
test_files:
|
105
|
+
test_files:
|
106
|
+
- spec/kametori_spec.rb
|
107
|
+
- spec/spec_helper.rb
|
71
108
|
has_rdoc:
|