coverband 4.2.0 → 4.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -9
- data/.travis.yml +10 -1
- data/Gemfile +3 -1
- data/Gemfile.rails4 +1 -0
- data/README.md +40 -15
- data/Rakefile +14 -3
- data/changes.md +47 -12
- data/coverband.gemspec +3 -1
- data/lib/coverband/adapters/base.rb +60 -36
- data/lib/coverband/adapters/file_store.rb +8 -8
- data/lib/coverband/adapters/redis_store.rb +18 -10
- data/lib/coverband/at_exit.rb +2 -11
- data/lib/coverband/collectors/coverage.rb +32 -36
- data/lib/coverband/collectors/delta.rb +34 -28
- data/lib/coverband/configuration.rb +76 -32
- data/lib/coverband/integrations/background.rb +8 -4
- data/lib/coverband/integrations/{middleware.rb → background_middleware.rb} +2 -6
- data/lib/coverband/integrations/bundler.rb +8 -0
- data/lib/coverband/integrations/report_middleware.rb +15 -0
- data/lib/coverband/integrations/resque.rb +3 -5
- data/lib/coverband/reporters/base.rb +39 -14
- data/lib/coverband/reporters/html_report.rb +21 -27
- data/lib/coverband/reporters/web.rb +13 -21
- data/lib/coverband/utils/file_list.rb +16 -5
- data/lib/coverband/utils/file_path_helper.rb +14 -3
- data/lib/coverband/utils/html_formatter.rb +25 -8
- data/lib/coverband/utils/lines_classifier.rb +5 -0
- data/lib/coverband/utils/railtie.rb +11 -12
- data/lib/coverband/utils/result.rb +1 -37
- data/lib/coverband/utils/results.rb +51 -0
- data/lib/coverband/utils/source_file.rb +31 -6
- data/lib/coverband/utils/tasks.rb +9 -10
- data/lib/coverband/version.rb +1 -1
- data/lib/coverband.rb +32 -21
- data/public/application.js +27 -0
- data/test/benchmarks/benchmark.rake +144 -26
- data/test/coverband/adapters/base_test.rb +73 -42
- data/test/coverband/adapters/file_store_test.rb +48 -37
- data/test/coverband/adapters/redis_store_test.rb +41 -10
- data/test/coverband/at_exit_test.rb +0 -2
- data/test/coverband/collectors/coverage_test.rb +57 -9
- data/test/coverband/collectors/delta_test.rb +36 -6
- data/test/coverband/configuration_test.rb +47 -7
- data/test/coverband/coverband_test.rb +14 -2
- data/test/coverband/integrations/background_middleware_test.rb +44 -0
- data/test/coverband/integrations/background_test.rb +1 -3
- data/test/coverband/integrations/report_middleware_test.rb +44 -0
- data/test/coverband/integrations/resque_worker_test.rb +4 -3
- data/test/coverband/integrations/test_resque_job.rb +3 -1
- data/test/coverband/reporters/base_test.rb +4 -4
- data/test/coverband/reporters/console_test.rb +1 -2
- data/test/coverband/reporters/html_test.rb +58 -19
- data/test/coverband/reporters/web_test.rb +0 -10
- data/test/coverband/utils/file_groups_test.rb +11 -5
- data/test/coverband/utils/file_list_test.rb +5 -5
- data/test/coverband/utils/html_formatter_test.rb +43 -0
- data/test/coverband/utils/result_test.rb +6 -47
- data/test/coverband/utils/results_test.rb +54 -0
- data/test/coverband/utils/s3_report_test.rb +2 -0
- data/test/coverband/utils/source_file_test.rb +50 -0
- data/test/dog.rb.erb +12 -0
- data/test/forked/rails_full_stack_test.rb +106 -0
- data/test/forked/rails_rake_full_stack_test.rb +40 -0
- data/test/integration/full_stack_test.rb +17 -15
- data/test/rails4_dummy/Rakefile +6 -0
- data/test/rails4_dummy/config/application.rb +8 -9
- data/test/rails4_dummy/config/coverband.rb +5 -3
- data/test/rails5_dummy/Rakefile +6 -0
- data/test/rails5_dummy/config/application.rb +6 -10
- data/test/rails5_dummy/config/coverband.rb +4 -2
- data/test/rails_test_helper.rb +22 -5
- data/test/test_helper.rb +42 -4
- data/test/unique_files.rb +17 -9
- data/views/file_list.erb +2 -2
- data/views/gem_list.erb +10 -1
- data/views/layout.erb +10 -3
- data/views/source_file.erb +13 -4
- data/views/source_file_loader.erb +1 -1
- metadata +52 -9
- data/test/coverband/integrations/middleware_test.rb +0 -96
- data/test/integration/rails_full_stack_test.rb +0 -95
|
@@ -11,6 +11,8 @@ module Coverband
|
|
|
11
11
|
module Utils
|
|
12
12
|
class SourceFile
|
|
13
13
|
include Coverband::Utils::FilePathHelper
|
|
14
|
+
|
|
15
|
+
# TODO: Refactor Line into its own file
|
|
14
16
|
# Representation of a single line in a source file including
|
|
15
17
|
# this specific line's source code, line_number and code coverage,
|
|
16
18
|
# with the coverage being either nil (coverage not applicable, e.g. comment
|
|
@@ -35,6 +37,7 @@ module Coverband
|
|
|
35
37
|
raise ArgumentError, 'Only String accepted for source' unless src.is_a?(String)
|
|
36
38
|
raise ArgumentError, 'Only Integer accepted for line_number' unless line_number.is_a?(Integer)
|
|
37
39
|
raise ArgumentError, 'Only Integer and nil accepted for coverage' unless coverage.is_a?(Integer) || coverage.nil?
|
|
40
|
+
|
|
38
41
|
@src = src
|
|
39
42
|
@line_number = line_number
|
|
40
43
|
@coverage = coverage
|
|
@@ -48,7 +51,7 @@ module Coverband
|
|
|
48
51
|
|
|
49
52
|
# Returns true if this is a line that has been covered
|
|
50
53
|
def covered?
|
|
51
|
-
!never? && !skipped? && coverage
|
|
54
|
+
!never? && !skipped? && coverage.positive?
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
# Returns true if this line is not relevant for coverage
|
|
@@ -64,7 +67,7 @@ module Coverband
|
|
|
64
67
|
# Returns true if this line was skipped, false otherwise. Lines are skipped if they are wrapped with
|
|
65
68
|
# # :nocov: comment lines.
|
|
66
69
|
def skipped?
|
|
67
|
-
|
|
70
|
+
skipped
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
# The status of this line - either covered, missed, skipped or never. Useful i.e. for direct use
|
|
@@ -90,18 +93,27 @@ module Coverband
|
|
|
90
93
|
|
|
91
94
|
def initialize(filename, file_data)
|
|
92
95
|
@filename = filename
|
|
96
|
+
@runtime_relavant_lines = nil
|
|
93
97
|
if file_data.is_a?(Hash)
|
|
94
98
|
@coverage = file_data['data']
|
|
95
99
|
@first_updated_at = @last_updated_at = NOT_AVAILABLE
|
|
96
100
|
@first_updated_at = Time.at(file_data['first_updated_at']) if file_data['first_updated_at']
|
|
97
101
|
@last_updated_at = Time.at(file_data['last_updated_at']) if file_data['last_updated_at']
|
|
98
102
|
else
|
|
103
|
+
# TODO: Deprecate this code path this was backwards compatability from 3-4
|
|
99
104
|
@coverage = file_data
|
|
100
105
|
@first_updated_at = NOT_AVAILABLE
|
|
101
106
|
@last_updated_at = NOT_AVAILABLE
|
|
102
107
|
end
|
|
103
108
|
end
|
|
104
109
|
|
|
110
|
+
def runtime_relavant_calculations(runtime_relavant_lines)
|
|
111
|
+
@runtime_relavant_lines = runtime_relavant_lines
|
|
112
|
+
yield self
|
|
113
|
+
ensure
|
|
114
|
+
@runtime_relavant_lines = nil
|
|
115
|
+
end
|
|
116
|
+
|
|
105
117
|
# The path to this source file relative to the projects directory
|
|
106
118
|
def project_filename
|
|
107
119
|
@filename.sub(/^#{Coverband.configuration.root}/, '')
|
|
@@ -148,7 +160,12 @@ module Coverband
|
|
|
148
160
|
|
|
149
161
|
return 0.0 if relevant_lines.zero?
|
|
150
162
|
|
|
151
|
-
|
|
163
|
+
# handle edge case where runtime in dev can go over 100%
|
|
164
|
+
[Float(covered_lines.size * 100.0 / relevant_lines.to_f), 100.0].min
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def formatted_covered_percent
|
|
168
|
+
covered_percent&.round(2)
|
|
152
169
|
end
|
|
153
170
|
|
|
154
171
|
def covered_strength
|
|
@@ -166,7 +183,7 @@ module Coverband
|
|
|
166
183
|
end
|
|
167
184
|
|
|
168
185
|
def relevant_lines
|
|
169
|
-
lines.size - never_lines.size - skipped_lines.size
|
|
186
|
+
@runtime_relavant_lines || (lines.size - never_lines.size - skipped_lines.size)
|
|
170
187
|
end
|
|
171
188
|
|
|
172
189
|
# Returns all covered lines as SimpleCov::SourceFile::Line
|
|
@@ -174,6 +191,14 @@ module Coverband
|
|
|
174
191
|
@covered_lines ||= lines.select(&:covered?)
|
|
175
192
|
end
|
|
176
193
|
|
|
194
|
+
def covered_lines_count
|
|
195
|
+
covered_lines&.count
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def line_coverage(index)
|
|
199
|
+
lines[index]&.coverage
|
|
200
|
+
end
|
|
201
|
+
|
|
177
202
|
# Returns all lines that should have been, but were not covered
|
|
178
203
|
# as instances of SimpleCov::SourceFile::Line
|
|
179
204
|
def missed_lines
|
|
@@ -216,7 +241,7 @@ module Coverband
|
|
|
216
241
|
# I had previously patched this in my local Rails app
|
|
217
242
|
def short_name
|
|
218
243
|
filename.sub(/^#{Coverband.configuration.root}/, '.')
|
|
219
|
-
.sub(%r{^.*\/gems}, '.')
|
|
244
|
+
.sub(%r{^.*\/gems\/}, '.')
|
|
220
245
|
.gsub(%r{^\.\/}, '')
|
|
221
246
|
end
|
|
222
247
|
|
|
@@ -229,7 +254,7 @@ module Coverband
|
|
|
229
254
|
end
|
|
230
255
|
|
|
231
256
|
def gem_name
|
|
232
|
-
gem? ? short_name.split('/').first : nil
|
|
257
|
+
gem? ? short_name.split('/').first.gsub(%r{^\.}, '') : nil
|
|
233
258
|
end
|
|
234
259
|
|
|
235
260
|
private
|
|
@@ -1,37 +1,36 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
namespace :coverband do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def environment
|
|
7
|
-
Rake.application['environment'].invoke if Rake::Task.task_defined?('environment')
|
|
8
|
-
end
|
|
4
|
+
# handles configuring in require => false and COVERBAND_DISABLE_AUTO_START cases
|
|
5
|
+
Coverband.configure unless Coverband.configured?
|
|
9
6
|
|
|
10
7
|
desc 'report runtime Coverband code coverage'
|
|
11
8
|
task :coverage do
|
|
12
|
-
environment
|
|
13
9
|
if Coverband.configuration.reporter == 'scov'
|
|
14
|
-
Coverband::Reporters::HTMLReport.
|
|
10
|
+
Coverband::Reporters::HTMLReport.new(Coverband.configuration.store).report
|
|
15
11
|
else
|
|
16
12
|
Coverband::Reporters::ConsoleReport.report(Coverband.configuration.store)
|
|
17
13
|
end
|
|
18
14
|
end
|
|
19
15
|
|
|
16
|
+
desc 'report runtime Coverband code coverage'
|
|
17
|
+
task :coverage_server do
|
|
18
|
+
Rack::Server.start app: Coverband::Reporters::Web.new, Port: ENV.fetch('COVERBAND_COVERAGE_PORT', 1022).to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
20
21
|
###
|
|
21
22
|
# clear data helpful for development or after configuration issues
|
|
22
23
|
###
|
|
23
24
|
desc 'reset Coverband coverage data, helpful for development, debugging, etc'
|
|
24
25
|
task :clear do
|
|
25
|
-
environment
|
|
26
26
|
Coverband.configuration.store.clear!
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
###
|
|
30
|
-
#
|
|
30
|
+
# Updates the data in the coverband store from one format to another
|
|
31
31
|
###
|
|
32
32
|
desc 'upgrade previous Coverband datastore to latest format'
|
|
33
33
|
task :migrate do
|
|
34
|
-
environment
|
|
35
34
|
Coverband.configuration.store.migrate!
|
|
36
35
|
end
|
|
37
36
|
end
|
data/lib/coverband/version.rb
CHANGED
data/lib/coverband.rb
CHANGED
|
@@ -23,24 +23,20 @@ require 'coverband/collectors/coverage'
|
|
|
23
23
|
require 'coverband/reporters/base'
|
|
24
24
|
require 'coverband/reporters/html_report'
|
|
25
25
|
require 'coverband/reporters/console_report'
|
|
26
|
-
require 'coverband/integrations/background'
|
|
27
|
-
require 'coverband/integrations/rack_server_check'
|
|
28
26
|
require 'coverband/reporters/web'
|
|
29
|
-
require 'coverband/integrations/middleware'
|
|
30
27
|
require 'coverband/integrations/background'
|
|
28
|
+
require 'coverband/integrations/background_middleware'
|
|
29
|
+
require 'coverband/integrations/rack_server_check'
|
|
31
30
|
|
|
32
31
|
module Coverband
|
|
32
|
+
@@configured = false
|
|
33
33
|
CONFIG_FILE = './config/coverband.rb'
|
|
34
|
-
RUNTIME_TYPE =
|
|
34
|
+
RUNTIME_TYPE = :runtime
|
|
35
35
|
EAGER_TYPE = :eager_loading
|
|
36
36
|
MERGED_TYPE = :merged
|
|
37
37
|
TYPES = [RUNTIME_TYPE, EAGER_TYPE]
|
|
38
38
|
ALL_TYPES = TYPES + [:merged]
|
|
39
39
|
|
|
40
|
-
class << self
|
|
41
|
-
attr_accessor :configuration_data
|
|
42
|
-
end
|
|
43
|
-
|
|
44
40
|
def self.configure(file = nil)
|
|
45
41
|
configuration_file = file || ENV.fetch('COVERBAND_CONFIG', CONFIG_FILE)
|
|
46
42
|
configuration
|
|
@@ -49,45 +45,60 @@ module Coverband
|
|
|
49
45
|
elsif File.exist?(configuration_file)
|
|
50
46
|
load configuration_file
|
|
51
47
|
else
|
|
52
|
-
configuration.logger
|
|
48
|
+
configuration.logger.debug('using default configuration')
|
|
53
49
|
end
|
|
54
|
-
|
|
50
|
+
@@configured = true
|
|
51
|
+
coverage_instance.reset_instance
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.configured?
|
|
55
|
+
@@configured
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
def self.report_coverage
|
|
58
|
-
|
|
58
|
+
def self.report_coverage
|
|
59
|
+
coverage_instance.report_coverage
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
def self.configuration
|
|
62
|
-
|
|
63
|
+
@configuration ||= Configuration.new
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
def self.start
|
|
66
67
|
Coverband::Collectors::Coverage.instance
|
|
67
|
-
# TODO Railtie sets up at_exit after forks, via middleware, perhaps this
|
|
68
|
+
# TODO: Railtie sets up at_exit after forks, via middleware, perhaps this should be
|
|
68
69
|
# added if not rails or if rails but not rackserverrunning
|
|
69
|
-
AtExit.register
|
|
70
|
-
Background.start if configuration.background_reporting_enabled && !RackServerCheck.running?
|
|
70
|
+
AtExit.register unless tasks_to_ignore?
|
|
71
|
+
Background.start if configuration.background_reporting_enabled && !RackServerCheck.running? && !tasks_to_ignore?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.tasks_to_ignore?
|
|
75
|
+
(defined?(Rake) &&
|
|
76
|
+
Rake.respond_to?(:application) &&
|
|
77
|
+
(Rake&.application&.top_level_tasks || []).any? { |task| Coverband::Configuration::IGNORE_TASKS.include?(task) })
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
def self.eager_loading_coverage!
|
|
74
|
-
|
|
81
|
+
coverage_instance.eager_loading!
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.eager_loading_coverage(&block)
|
|
85
|
+
coverage_instance.eager_loading(&block)
|
|
75
86
|
end
|
|
76
87
|
|
|
77
88
|
def self.runtime_coverage!
|
|
78
|
-
|
|
89
|
+
coverage_instance.runtime!
|
|
79
90
|
end
|
|
80
91
|
|
|
81
|
-
def self.
|
|
92
|
+
private_class_method def self.coverage_instance
|
|
82
93
|
Coverband::Collectors::Coverage.instance
|
|
83
94
|
end
|
|
84
|
-
|
|
85
95
|
unless ENV['COVERBAND_DISABLE_AUTO_START']
|
|
86
96
|
# Coverband should be setup as early as possible
|
|
87
97
|
# to capture usage of things loaded by initializers or other Rails engines
|
|
88
98
|
configure
|
|
89
99
|
start
|
|
90
100
|
require 'coverband/utils/railtie' if defined? ::Rails::Railtie
|
|
91
|
-
require 'coverband/integrations/resque' if defined? Resque
|
|
101
|
+
require 'coverband/integrations/resque' if defined? ::Resque
|
|
102
|
+
require 'coverband/integrations/bundler' if defined? ::Bundler
|
|
92
103
|
end
|
|
93
104
|
end
|
data/public/application.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
$(document).ready(function() {
|
|
2
|
+
// remove the url params like notice=message so they don't stick around
|
|
3
|
+
window.history.replaceState(
|
|
4
|
+
"object or string",
|
|
5
|
+
"Coverband",
|
|
6
|
+
window.location.href.replace(/notice=.*/, "")
|
|
7
|
+
);
|
|
8
|
+
$(".notice")
|
|
9
|
+
.delay(3000)
|
|
10
|
+
.fadeOut("slow");
|
|
11
|
+
|
|
2
12
|
$(".del").click(function() {
|
|
3
13
|
if (!confirm("Do you want to delete")) {
|
|
4
14
|
return false;
|
|
@@ -13,8 +23,25 @@ $(document).ready(function() {
|
|
|
13
23
|
aoColumns: [
|
|
14
24
|
null,
|
|
15
25
|
{ sType: "percent" },
|
|
26
|
+
{ sType: "percent" },
|
|
27
|
+
null,
|
|
28
|
+
null,
|
|
29
|
+
null,
|
|
16
30
|
null,
|
|
17
31
|
null,
|
|
32
|
+
null
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Configuration for fancy sortable tables for source file groups
|
|
37
|
+
$(".gem_list").dataTable({
|
|
38
|
+
aaSorting: [[1, "asc"]],
|
|
39
|
+
bPaginate: false,
|
|
40
|
+
bJQueryUI: true,
|
|
41
|
+
aoColumns: [
|
|
42
|
+
null,
|
|
43
|
+
{ sType: "percent" },
|
|
44
|
+
{ sType: "percent" },
|
|
18
45
|
null,
|
|
19
46
|
null,
|
|
20
47
|
null,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
namespace :benchmarks do
|
|
3
4
|
# https://github.com/evanphx/benchmark-ips
|
|
4
5
|
# Enable and start GC before each job run. Disable GC afterwards.
|
|
@@ -13,11 +14,9 @@ namespace :benchmarks do
|
|
|
13
14
|
run_gc
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
def warmup_stats(*)
|
|
17
|
-
end
|
|
17
|
+
def warmup_stats(*); end
|
|
18
18
|
|
|
19
|
-
def add_report(*)
|
|
20
|
-
end
|
|
19
|
+
def add_report(*); end
|
|
21
20
|
|
|
22
21
|
private
|
|
23
22
|
|
|
@@ -33,11 +32,7 @@ namespace :benchmarks do
|
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
def clone_classifier
|
|
36
|
-
#
|
|
37
|
-
unless Dir.exist? classifier_dir
|
|
38
|
-
system "git clone https://github.com/jekyll/classifier-reborn.git #{classifier_dir}"
|
|
39
|
-
end
|
|
40
|
-
# rubocop:enable Style/IfUnlessModifier
|
|
35
|
+
system "git clone https://github.com/jekyll/classifier-reborn.git #{classifier_dir}" unless Dir.exist? classifier_dir
|
|
41
36
|
end
|
|
42
37
|
|
|
43
38
|
# desc 'setup standard benchmark'
|
|
@@ -56,9 +51,9 @@ namespace :benchmarks do
|
|
|
56
51
|
# moving from 5 second of time to 12 still shows slower based on when classifier is required
|
|
57
52
|
# make sure to be plugged in while benchmarking ;) Otherwise you get very unreliable results
|
|
58
53
|
require 'classifier-reborn'
|
|
59
|
-
if ENV['COVERAGE']
|
|
54
|
+
if ENV['COVERAGE'] || ENV['ONESHOT']
|
|
60
55
|
require 'coverage'
|
|
61
|
-
::Coverage.start
|
|
56
|
+
::Coverage.start(oneshot_lines: !!ENV['ONESHOT'])
|
|
62
57
|
end
|
|
63
58
|
require 'redis'
|
|
64
59
|
require 'coverband'
|
|
@@ -79,9 +74,10 @@ namespace :benchmarks do
|
|
|
79
74
|
task :setup_redis do
|
|
80
75
|
Coverband.configure do |config|
|
|
81
76
|
config.root = Dir.pwd
|
|
82
|
-
config.reporting_frequency = 100.0
|
|
83
77
|
config.logger = $stdout
|
|
84
78
|
config.store = benchmark_redis_store
|
|
79
|
+
config.use_oneshot_lines_coverage = true if ENV['ONESHOT']
|
|
80
|
+
config.simulate_oneshot_lines_coverage = true if ENV['SIMULATE_ONESHOT']
|
|
85
81
|
end
|
|
86
82
|
end
|
|
87
83
|
|
|
@@ -89,7 +85,6 @@ namespace :benchmarks do
|
|
|
89
85
|
task :setup_file do
|
|
90
86
|
Coverband.configure do |config|
|
|
91
87
|
config.root = Dir.pwd
|
|
92
|
-
config.reporting_frequency = 100.0
|
|
93
88
|
config.logger = $stdout
|
|
94
89
|
file_path = '/tmp/benchmark_store.json'
|
|
95
90
|
config.store = Coverband::Adapters::FileStore.new(file_path)
|
|
@@ -134,7 +129,7 @@ namespace :benchmarks do
|
|
|
134
129
|
x.config(time: 12, warmup: 5, suite: suite)
|
|
135
130
|
x.report 'coverband' do
|
|
136
131
|
work
|
|
137
|
-
Coverband.report_coverage
|
|
132
|
+
Coverband.report_coverage
|
|
138
133
|
end
|
|
139
134
|
x.report 'no coverband' do
|
|
140
135
|
work
|
|
@@ -160,6 +155,7 @@ namespace :benchmarks do
|
|
|
160
155
|
def adjust_report(report)
|
|
161
156
|
report.keys.each do |file|
|
|
162
157
|
next unless rand < 0.15
|
|
158
|
+
|
|
163
159
|
report[file] = fake_line_numbers
|
|
164
160
|
end
|
|
165
161
|
report
|
|
@@ -170,11 +166,7 @@ namespace :benchmarks do
|
|
|
170
166
|
# this is a hack because in the benchmark we don't have real files
|
|
171
167
|
###
|
|
172
168
|
def store.file_hash(file)
|
|
173
|
-
|
|
174
|
-
@file_hash_cache[file]
|
|
175
|
-
else
|
|
176
|
-
@file_hash_cache[file] = Digest::MD5.file(__FILE__).hexdigest
|
|
177
|
-
end
|
|
169
|
+
@file_hash_cache[file] || @file_hash_cache[file] = Digest::MD5.file(__FILE__).hexdigest
|
|
178
170
|
end
|
|
179
171
|
|
|
180
172
|
def store.full_path_to_relative(file)
|
|
@@ -214,11 +206,54 @@ namespace :benchmarks do
|
|
|
214
206
|
end.pretty_print
|
|
215
207
|
data = $stdout.string
|
|
216
208
|
$stdout = previous_out
|
|
217
|
-
|
|
209
|
+
unless data.match('Total retained: 0 bytes')
|
|
210
|
+
puts data
|
|
211
|
+
raise 'leaking memory!!!'
|
|
212
|
+
end
|
|
218
213
|
ensure
|
|
219
214
|
$stdout = previous_out
|
|
220
215
|
end
|
|
221
216
|
|
|
217
|
+
def measure_memory_report_coverage
|
|
218
|
+
require 'memory_profiler'
|
|
219
|
+
report = fake_report
|
|
220
|
+
store = benchmark_redis_store
|
|
221
|
+
store.clear!
|
|
222
|
+
mock_files(store)
|
|
223
|
+
|
|
224
|
+
# warmup
|
|
225
|
+
3.times { Coverband.report_coverage }
|
|
226
|
+
|
|
227
|
+
previous_out = $stdout
|
|
228
|
+
capture = StringIO.new
|
|
229
|
+
$stdout = capture
|
|
230
|
+
|
|
231
|
+
MemoryProfiler.report do
|
|
232
|
+
10.times do
|
|
233
|
+
Coverband.report_coverage
|
|
234
|
+
###
|
|
235
|
+
# Set to nil not {} as it is easier to verify that no memory is retained when nil gets released
|
|
236
|
+
# don't use Coverband::Collectors::Delta.reset which sets to {}
|
|
237
|
+
# we clear this as this one variable is expected to retain memory and is a false positive
|
|
238
|
+
###
|
|
239
|
+
Coverband::Collectors::Delta.class_variable_set(:@@previous_coverage, nil)
|
|
240
|
+
end
|
|
241
|
+
end.pretty_print
|
|
242
|
+
data = $stdout.string
|
|
243
|
+
$stdout = previous_out
|
|
244
|
+
unless data.match('Total retained: 0 bytes')
|
|
245
|
+
puts data
|
|
246
|
+
raise 'leaking memory!!!'
|
|
247
|
+
end
|
|
248
|
+
ensure
|
|
249
|
+
$stdout = previous_out
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
###
|
|
253
|
+
# TODO: This currently fails, as it holds a string in redis adapter
|
|
254
|
+
# but really Coverband shouldn't be configured multiple times and the leak is small
|
|
255
|
+
# not including in test suite but we can try to figure it out and fix.
|
|
256
|
+
###
|
|
222
257
|
def measure_configure_memory
|
|
223
258
|
require 'memory_profiler'
|
|
224
259
|
# warmup
|
|
@@ -232,24 +267,79 @@ namespace :benchmarks do
|
|
|
232
267
|
10.times do
|
|
233
268
|
Coverband.configure do |config|
|
|
234
269
|
redis_url = ENV['CACHE_REDIS_URL'] || ENV['REDIS_URL']
|
|
235
|
-
config.store = Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_namespace: '
|
|
270
|
+
config.store = Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_namespace: 'coverband_bench_data')
|
|
236
271
|
end
|
|
237
272
|
end
|
|
238
273
|
end.pretty_print
|
|
239
274
|
data = $stdout.string
|
|
240
275
|
$stdout = previous_out
|
|
241
|
-
|
|
242
|
-
|
|
276
|
+
unless data.match('Total retained: 0 bytes')
|
|
277
|
+
puts data
|
|
278
|
+
raise 'leaking memory!!!'
|
|
279
|
+
end
|
|
243
280
|
ensure
|
|
244
281
|
$stdout = previous_out
|
|
245
282
|
end
|
|
246
283
|
|
|
284
|
+
desc 'checks memory of collector'
|
|
285
|
+
task memory_check: [:setup] do
|
|
286
|
+
require 'pry-byebug'
|
|
287
|
+
require 'objspace'
|
|
288
|
+
puts 'memory load check'
|
|
289
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
290
|
+
data = File.read('./tmp/debug_data.json')
|
|
291
|
+
# about 2mb
|
|
292
|
+
puts(ObjectSpace.memsize_of(data) / 2**20)
|
|
293
|
+
|
|
294
|
+
json_data = JSON.parse(data)
|
|
295
|
+
# this seems to just show the value of the pointer
|
|
296
|
+
# puts(ObjectSpace.memsize_of(json_data) / 2**20)
|
|
297
|
+
# implies json takes 10-12 mb
|
|
298
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
299
|
+
|
|
300
|
+
json_data = nil
|
|
301
|
+
GC.start
|
|
302
|
+
json_data = JSON.parse(data)
|
|
303
|
+
# this seems to just show the value of the pointer
|
|
304
|
+
# puts(ObjectSpace.memsize_of(json_data) / 2**20)
|
|
305
|
+
# implies json takes 10-12 mb
|
|
306
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
307
|
+
|
|
308
|
+
json_data = nil
|
|
309
|
+
GC.start
|
|
310
|
+
json_data = JSON.parse(data)
|
|
311
|
+
# this seems to just show the value of the pointer
|
|
312
|
+
# puts(ObjectSpace.memsize_of(json_data) / 2**20)
|
|
313
|
+
# implies json takes 10-12 mb
|
|
314
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
315
|
+
|
|
316
|
+
json_data = nil
|
|
317
|
+
GC.start
|
|
318
|
+
json_data = JSON.parse(data)
|
|
319
|
+
# this seems to just show the value of the pointer
|
|
320
|
+
# puts(ObjectSpace.memsize_of(json_data) / 2**20)
|
|
321
|
+
# implies json takes 10-12 mb
|
|
322
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
323
|
+
|
|
324
|
+
json_data = nil
|
|
325
|
+
GC.start
|
|
326
|
+
puts(ObjectSpace.memsize_of_all / 2**20)
|
|
327
|
+
debugger
|
|
328
|
+
puts 'done'
|
|
329
|
+
end
|
|
330
|
+
|
|
247
331
|
desc 'runs memory reporting on Redis store'
|
|
248
332
|
task memory_reporting: [:setup] do
|
|
249
333
|
puts 'runs memory benchmarking to ensure we dont leak'
|
|
250
334
|
measure_memory
|
|
251
335
|
end
|
|
252
336
|
|
|
337
|
+
desc 'runs memory reporting on report_coverage'
|
|
338
|
+
task memory_reporting_report_coverage: [:setup] do
|
|
339
|
+
puts 'runs memory benchmarking on report_coverage to ensure we dont leak'
|
|
340
|
+
measure_memory_report_coverage
|
|
341
|
+
end
|
|
342
|
+
|
|
253
343
|
desc 'runs memory reporting on configure'
|
|
254
344
|
task memory_configure_reporting: [:setup] do
|
|
255
345
|
puts 'runs memory benchmarking on configure to ensure we dont leak'
|
|
@@ -259,7 +349,12 @@ namespace :benchmarks do
|
|
|
259
349
|
desc 'runs memory leak check via Rails tests'
|
|
260
350
|
task memory_rails: [:setup] do
|
|
261
351
|
puts 'runs memory rails test to ensure we dont leak'
|
|
262
|
-
puts `COVERBAND_MEMORY_TEST=true bundle exec
|
|
352
|
+
puts `COVERBAND_MEMORY_TEST=true bundle exec test/forked/rails_full_stack_test.rb`
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
desc 'runs memory leak checks'
|
|
356
|
+
task memory: %i[memory_reporting memory_reporting_report_coverage memory_rails] do
|
|
357
|
+
puts 'done'
|
|
263
358
|
end
|
|
264
359
|
|
|
265
360
|
desc 'runs benchmarks on reporting large sets of files to redis'
|
|
@@ -269,13 +364,36 @@ namespace :benchmarks do
|
|
|
269
364
|
end
|
|
270
365
|
|
|
271
366
|
# desc 'runs benchmarks on default redis setup'
|
|
272
|
-
task run_redis: [
|
|
367
|
+
task run_redis: %i[setup setup_redis] do
|
|
273
368
|
puts 'Coverband configured with default Redis store'
|
|
274
369
|
run_work(true)
|
|
275
370
|
end
|
|
276
371
|
|
|
372
|
+
def run_big
|
|
373
|
+
require 'memory_profiler'
|
|
374
|
+
require './test/unique_files'
|
|
375
|
+
|
|
376
|
+
4000.times { |index| require_unique_file('dog.rb.erb', dog_number: index) }
|
|
377
|
+
# warmup
|
|
378
|
+
3.times { Coverband.report_coverage }
|
|
379
|
+
dogs = 400.times.map { |index| Object.const_get("Dog#{index}") }
|
|
380
|
+
MemoryProfiler.report do
|
|
381
|
+
10.times do
|
|
382
|
+
dogs.each(&:bark)
|
|
383
|
+
Coverband.report_coverage
|
|
384
|
+
end
|
|
385
|
+
end.pretty_print
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
task run_big: %i[setup setup_redis] do
|
|
389
|
+
# ensure we cleared from last run
|
|
390
|
+
benchmark_redis_store.clear!
|
|
391
|
+
|
|
392
|
+
run_big
|
|
393
|
+
end
|
|
394
|
+
|
|
277
395
|
# desc 'runs benchmarks file store'
|
|
278
|
-
task run_file: [
|
|
396
|
+
task run_file: %i[setup setup_file] do
|
|
279
397
|
puts 'Coverband configured with file store'
|
|
280
398
|
run_work(true)
|
|
281
399
|
end
|