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 ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Kametori
2
2
 
3
- TODO: Write a gem description
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
- TODO: Write usage instructions here
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
@@ -17,4 +17,6 @@ Gem::Specification.new do |gem|
17
17
  gem.version = Kametori::VERSION
18
18
 
19
19
  gem.add_development_dependency("rspec", [">= 2.2.0"])
20
+ gem.add_development_dependency("timecop")
21
+ gem.add_development_dependency("debugger")
20
22
  end
@@ -1,3 +1,3 @@
1
1
  module Kametori
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/kametori.rb CHANGED
@@ -2,36 +2,89 @@ require "kametori/version"
2
2
 
3
3
  module Kametori
4
4
  # exception classes
5
- class Error < RuntimeError
6
- end
7
- class Timeout < RuntimeError
8
-
5
+ class Timeout < StandardError
9
6
  end
10
7
 
11
8
  class << self
12
- def limits=(limits)
13
- raise Error if !limits.is_a? Array
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 limits
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 benchmark_scenario(scenario, options={})
22
- under_test = @limits.find{ |limit| limit[:tag] == scenario.tag}
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
- before = Time.now
25
- yield if block_given?
26
- after = Time.now
27
- elapsed = after - before
28
- if options[:raise]
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
@@ -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.2
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: