kametori 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|