minitest-perf 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .minitest-perf*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in minitest-perf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Albert Llop
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # MiniTest::Perf
2
+
3
+ `minitest-perf` stores information about your minitest runs so that you can later analyze and see where
4
+ the pain points are. It's in pretty early beta status, so I'm more than glad to receive bug reportsand
5
+ feature suggestions.
6
+
7
+ For now it should work with later versions of MiniTest 4, since the biggest test suite I have available
8
+ is with this version. MiniTest 5 probably doesn't work yet.
9
+
10
+ ## How it works
11
+
12
+ Every test that is executed is stored in a sqlite database for later query. Just require `minitet/perf`
13
+ somewhere in your test_helper, and you're good to go. Internally, `minitest/perf` includes itself as
14
+ just another module and starts feeding the sqlite database.
15
+
16
+ The sqlite database is stored by default as `.minitest-perf.db`.
17
+
18
+ An executable is provided that does prints a very basic analysis of the information it already has,
19
+ but the sqlite database is perfectly normal, so you can do your own queries.
20
+
21
+ This is an example:
22
+
23
+ ```
24
+ $ be minitest-perf
25
+ Slowest individual tests
26
+
27
+ 190.98ms | JobsCategoriesControllerLoggedOutTest#test_show_action_should_render_show_page_without_contact_distance_call_for_logged_out_users
28
+ 161.12ms | APostingFrozenNotificationActiveRecordTestCasTest#test_should_log_the_exception_and_any_additional_data_when_a_PerlBackend::Error_is_thrown
29
+ 147.39ms | VersionsTest#test_rubygems_version
30
+ 132.52ms | JobsCategoriesControllerLoggedInTest#test_show_action_should_show__all__postings_of_a_category_for_logged_in_users
31
+ 124.21ms | JobsCategoriesControllerLoggedInTest#test_should_show_all_postings_of_selected_subcategories
32
+ 122.99ms | OrderReachedAboutToRunOutOfPostingsBeforeLast24HoursTest#test_should_return_false_if_at_amount_left_is_15_percent_of_amount,_and_last_posting_created_within_24_hours
33
+ 121.98ms | JobsCategoriesControllerLoggedOutTest#test_show_action_should_show_all_public_postings_for_logged_out_users
34
+ 116.97ms | JobsCategoriesControllerUserDependantLanguageTest#test_should_show_postings_in_categories_user's_browser_language_and_default_language_en_logged-out
35
+ 110.12ms | JobsCategoriesControllerUserDependantLanguageTest#test_caching_of_cities_is_dependant_on_the_user's_language_logged-in
36
+ 109.20ms | PostingsControllerNewActionTest#test_should_take_the_posters_business_country_as_default_country_for_new_postings_on_GET
37
+
38
+
39
+ Slowest test suites
40
+
41
+ 116.07ms | 3 | JobsCategoriesControllerLoggedOutTest
42
+ 113.54ms | 2 | JobsCategoriesControllerUserDependantLanguageTest
43
+ 98.19ms | 1 | PublishToCompanyPostingControllerTest
44
+ 97.81ms | 1 | ShowActionPagingForPostingSearchTest
45
+ 79.66ms | 1 | PostingMostViewedNamedScopeTest
46
+ 78.92ms | 3 | OrderReachedAboutToRunOutOfPostingsBeforeLast24HoursTest
47
+ 68.92ms | 1 | Jobs::ProductAvailabilityTimePeriodOverlapTest
48
+ 68.53ms | 1 | TheMotherOfAllBillingCycleTests
49
+ 66.77ms | 4 | CategoriesTest
50
+ 62.60ms | 2 | RecommendationsActivityBoxFallbackTest
51
+ ```
52
+
53
+ ## TODO
54
+
55
+ These are nice to haves I'd like to implement in the future:
56
+
57
+ * Customizable db file
58
+ * Store also in mysql
59
+ * Web interface
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.pattern = "test/**/*_test.rb"
7
+ t.verbose = true
8
+ end
9
+ Rake::Task['test'].comment = "Run all tests"
10
+
11
+ task :default => :test
data/bin/minitest-perf ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'minitest/perf'
4
+
5
+ Minitest::Perf::Cli.new.run
@@ -0,0 +1,21 @@
1
+ module MiniTest
2
+ module Perf
3
+ class Cli
4
+ def run
5
+ puts "Slowest individual tests"
6
+ puts
7
+ Statistics.slowest_tests.each do |suite, test_name, time|
8
+ printf "% 12.2fms | %s#%s\n", time * 1000, suite, test_name
9
+ end
10
+
11
+ puts
12
+ puts
13
+ puts "Slowest test suites"
14
+ puts
15
+ Statistics.slowest_suites.each do |suite_name, tests_count, avg_test_time|
16
+ printf "% 12.2fms | % 4i | %s\n", avg_test_time * 1000, tests_count, suite_name
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ require 'sqlite3'
2
+
3
+ module MiniTest
4
+ module Perf
5
+ module Persistence
6
+ class << self
7
+ def write(test)
8
+ db.execute <<-SQL, [test.run.to_s, test.suite, test.name, test.total]
9
+ INSERT INTO tests (run, suite, name, total)
10
+ VALUES (?, ?, ?, ?)
11
+ SQL
12
+ end
13
+
14
+ def read_tests
15
+ db.execute("SELECT * FROM TESTS").map do |run, suite, name, total|
16
+ Test.new(run, suite, name, total)
17
+ end
18
+ end
19
+
20
+ def sql(query)
21
+ db.execute query
22
+ end
23
+
24
+ private
25
+
26
+ def db
27
+ @@db ||= begin
28
+ db = SQLite3::Database.new ".minitest-perf.db"
29
+ db.execute <<-SQL
30
+ create table if not exists tests (
31
+ run varchar(255),
32
+ suite varchar(255),
33
+ name varchar(255),
34
+ total float
35
+ );
36
+ SQL
37
+ db
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,19 @@
1
+ module MiniTest
2
+ module Perf
3
+ module Plugin
4
+ def before_setup
5
+ current_perf_run.start(self.class.name, __name__)
6
+ super
7
+ end
8
+
9
+ def after_teardown
10
+ super
11
+ current_perf_run.finish(self.class.name, __name__)
12
+ end
13
+
14
+ def current_perf_run
15
+ @@current_perf_run ||= MiniTest::Perf::Run.new
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module MiniTest
2
+ module Perf
3
+ class Run
4
+ attr_reader :tests
5
+
6
+ def initialize(started_at = Time.now)
7
+ @tests = []
8
+ @started_at = started_at
9
+ end
10
+
11
+ def start(suite, name, now = Time.now)
12
+ @test_start = now
13
+ end
14
+
15
+ def finish(suite, name, now = Time.now)
16
+ test_total = now - @test_start
17
+
18
+ add_test Test.new(
19
+ @started_at, suite, name, test_total
20
+ ).tap(&:persist)
21
+ end
22
+
23
+ def add_test(test)
24
+ @tests << test
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ module MiniTest
2
+ module Perf
3
+ module Statistics
4
+ class << self
5
+ def slowest_tests
6
+ Persistence.sql(<<-SQL)
7
+ SELECT suite, name, avg(total) as avg_total
8
+ FROM tests
9
+ GROUP BY suite, name
10
+ ORDER BY avg_total DESC
11
+ LIMIT 10
12
+ SQL
13
+ end
14
+
15
+ def slowest_suites
16
+ Persistence.sql(<<-SQL)
17
+ SELECT suite, AVG(test_count), AVG(avg_total_per_test_run) as avg_total
18
+ FROM (
19
+ SELECT run, suite, COUNT(name) AS test_count, AVG(total) as avg_total_per_test_run
20
+ FROM tests
21
+ GROUP BY run, suite
22
+ ) as temp
23
+ GROUP BY suite
24
+ ORDER BY avg_total desc
25
+ LIMIT 10
26
+ SQL
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ module MiniTest
2
+ module Perf
3
+ class Test
4
+ attr_reader :run, :suite, :name, :total
5
+
6
+ def initialize(run, suite, name, total)
7
+ @run = run
8
+ @suite = suite
9
+ @name = name
10
+ @total = total
11
+ end
12
+
13
+ def persist
14
+ Persistence.write(self)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module MiniTest
2
+ module Perf
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'minitest/perf/version'
2
+ require 'minitest/unit'
3
+
4
+ module MiniTest::Perf
5
+ autoload :Run, 'minitest/perf/run'
6
+ autoload :Test, 'minitest/perf/test'
7
+ autoload :Suite, 'minitest/perf/suite'
8
+ autoload :Cli, 'minitest/perf/cli'
9
+ autoload :Plugin, 'minitest/perf/plugin'
10
+ autoload :Persistence, 'minitest/perf/persistence'
11
+ autoload :Statistics, 'minitest/perf/statistics'
12
+ end
13
+
14
+ class MiniTest::Unit::TestCase
15
+ include MiniTest::Perf::Plugin
16
+ end
@@ -0,0 +1 @@
1
+ require 'minitest/perf'
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'minitest/perf/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "minitest-perf"
8
+ spec.version = MiniTest::Perf::VERSION
9
+ spec.authors = ["Albert Llop"]
10
+ spec.email = ["mrsimo@gmail.com"]
11
+ spec.description = %q{Save test run data to find slow tests and other interesting information}
12
+ spec.summary = <<-SUMMARY
13
+ Require minitest/perf when running your tests, and a handful of data will be recorded
14
+ for later query and study. Find particularly slow tests, and understand your tests
15
+ even more.
16
+ SUMMARY
17
+ spec.homepage = "https://github.com/mrsimo/minitest-perf"
18
+ spec.license = "MIT"
19
+
20
+ spec.files = `git ls-files`.split($/)
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "mocha"
28
+ spec.add_development_dependency "debugger"
29
+ spec.add_dependency "minitest", "~> 4.0"
30
+ spec.add_dependency "sqlite3"
31
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+ require 'sqlite3'
3
+
4
+ module MiniTest::Perf
5
+ class PersistenceTest < MiniTest::Unit::TestCase
6
+ def setup
7
+ @test = Test.new('run', 'suite', 'name', 10)
8
+ Persistence.sql "delete from tests"
9
+ end
10
+
11
+ def test_exposes_a_sql_interface
12
+ assert_instance_of Array, Persistence.sql('select * from tests')
13
+ end
14
+
15
+ def test_stores_the_test_as_a_new_row
16
+ Persistence.write(@test)
17
+
18
+ result = Persistence.sql "SELECT * FROM tests"
19
+
20
+ assert_equal 1, result.size
21
+
22
+ run, suite, name, total = result.first
23
+
24
+ assert_equal 'run', run
25
+ assert_equal 'suite', suite
26
+ assert_equal 'name', name
27
+ assert_equal 10, total
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class PluginTest < MiniTest::Unit::TestCase
4
+ def test_minitest_has_the_plugin_included
5
+ assert_includes MiniTest::Unit::TestCase.included_modules, MiniTest::Perf::Plugin
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ module MiniTest::Perf
4
+ class RunTest < MiniTest::Unit::TestCase
5
+ def test_a_new_run_has_no_tests
6
+ run = Run.new
7
+
8
+ assert_empty run.tests
9
+ end
10
+
11
+ def test_creates_a_new_test_calling_start_and_finish
12
+ run = Run.new(Time.at(0))
13
+ run.start('SuiteName', 'test_something', Time.at(1))
14
+
15
+ assert_empty run.tests
16
+
17
+ run.finish('SuiteName', 'test_something', Time.at(8))
18
+
19
+ assert_equal 1, run.tests.size
20
+
21
+ test = run.tests.last
22
+
23
+ assert_equal 'SuiteName', test.suite
24
+ assert_equal 'test_something', test.name
25
+ assert_equal Time.at(0), test.run
26
+ assert_equal 7, test.total
27
+ end
28
+
29
+ def test_persists_the_test
30
+ run = Run.new
31
+ run.start('SuiteName', 'test_something')
32
+
33
+ Test.any_instance.expects(:persist)
34
+ run.finish('SuiteName', 'test_something')
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ module MiniTest::Perf
4
+ class TestTest < MiniTest::Unit::TestCase
5
+ def test_creation
6
+ test = Test.new('run', 'suite', 'name', 10)
7
+
8
+ assert_equal 'run', test.run
9
+ assert_equal 'suite', test.suite
10
+ assert_equal 'name', test.name
11
+ assert_equal 10, test.total
12
+ end
13
+
14
+ def test_persists_calls_persistence
15
+ test = Test.new('run', 'suite', 'name', 10)
16
+
17
+ Persistence.expects(:write).with(test)
18
+
19
+ test.persist
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'minitest/autorun'
4
+ require 'minitest/pride'
5
+ require 'mocha/setup'
6
+ require 'debugger'
7
+
8
+ require 'minitest/perf'
9
+
10
+ ##
11
+ # We disable the real plugin or stuff gets all confusing
12
+ # in the tests when mocking and creating expectations.
13
+ class FakeRun
14
+ def start(*pars); end
15
+ def finish(*pars); end
16
+ end
17
+
18
+ MiniTest::Perf::Plugin.class_eval do
19
+ def current_perf_run
20
+ @current_perf_run ||= FakeRun.new
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: minitest-perf
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Albert Llop
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ type: :development
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '1.3'
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ type: :development
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
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: mocha
48
+ type: :development
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: debugger
64
+ type: :development
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: minitest
80
+ type: :runtime
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: '4.0'
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '4.0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: sqlite3
96
+ type: :runtime
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Save test run data to find slow tests and other interesting information
111
+ email:
112
+ - mrsimo@gmail.com
113
+ executables:
114
+ - minitest-perf
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - bin/minitest-perf
124
+ - lib/minitest-perf.rb
125
+ - lib/minitest/perf.rb
126
+ - lib/minitest/perf/cli.rb
127
+ - lib/minitest/perf/persistence.rb
128
+ - lib/minitest/perf/plugin.rb
129
+ - lib/minitest/perf/run.rb
130
+ - lib/minitest/perf/statistics.rb
131
+ - lib/minitest/perf/test.rb
132
+ - lib/minitest/perf/version.rb
133
+ - minitest-perf.gemspec
134
+ - test/perf/persistence_test.rb
135
+ - test/perf/plugin_test.rb
136
+ - test/perf/run_test.rb
137
+ - test/perf/test_test.rb
138
+ - test/test_helper.rb
139
+ homepage: https://github.com/mrsimo/minitest-perf
140
+ licenses:
141
+ - MIT
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.23
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Require minitest/perf when running your tests, and a handful of data will
164
+ be recorded for later query and study. Find particularly slow tests, and understand
165
+ your tests even more.
166
+ test_files:
167
+ - test/perf/persistence_test.rb
168
+ - test/perf/plugin_test.rb
169
+ - test/perf/run_test.rb
170
+ - test/perf/test_test.rb
171
+ - test/test_helper.rb