coverband 4.1.1 → 4.2.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -4
- data/.travis.yml +2 -4
- data/README.md +8 -33
- data/Rakefile +1 -1
- data/changes.md +10 -26
- data/coverband.gemspec +0 -4
- data/lib/coverband.rb +0 -5
- data/lib/coverband/adapters/base.rb +4 -20
- data/lib/coverband/adapters/file_store.rb +0 -8
- data/lib/coverband/adapters/redis_store.rb +2 -33
- data/lib/coverband/at_exit.rb +1 -1
- data/lib/coverband/collectors/coverage.rb +1 -7
- data/lib/coverband/configuration.rb +2 -30
- data/lib/coverband/integrations/background.rb +1 -6
- data/lib/coverband/integrations/resque.rb +2 -7
- data/lib/coverband/reporters/base.rb +38 -8
- data/lib/coverband/reporters/html_report.rb +1 -1
- data/lib/coverband/reporters/web.rb +1 -13
- data/lib/coverband/utils/file_groups.rb +12 -20
- data/lib/coverband/utils/html_formatter.rb +1 -9
- data/lib/coverband/utils/railtie.rb +1 -1
- data/lib/coverband/utils/tasks.rb +0 -9
- data/lib/coverband/version.rb +1 -1
- data/test/benchmarks/benchmark.rake +1 -36
- data/test/test_helper.rb +12 -5
- data/test/{coverband/adapters/base_test.rb → unit/adapters_base_test.rb} +1 -1
- data/test/{coverband/adapters/file_store_test.rb → unit/adapters_file_store_test.rb} +1 -1
- data/test/{coverband/adapters/redis_store_test.rb → unit/adapters_redis_store_test.rb} +1 -1
- data/test/{coverband → unit}/at_exit_test.rb +0 -0
- data/test/{coverband/integrations → unit}/background_test.rb +1 -1
- data/test/unit/collectors_coverage_test.rb +48 -0
- data/test/{coverband → unit}/configuration_test.rb +3 -13
- data/test/{coverband → unit}/coverband_test.rb +0 -0
- data/test/{dog.rb → unit/dog.rb} +0 -0
- data/test/{integration → unit}/full_stack_test.rb +2 -4
- data/test/{coverband/integrations → unit}/middleware_test.rb +1 -1
- data/test/{coverband/integrations/rack_server_check_test.rb → unit/rack_server_checkout_test.rb} +1 -1
- data/test/{integration → unit}/rails_full_stack_test.rb +3 -4
- data/test/{integration → unit}/rails_gems_full_stack_test.rb +1 -2
- data/test/unit/reports_base_test.rb +117 -0
- data/test/{coverband/reporters/console_test.rb → unit/reports_console_test.rb} +5 -6
- data/test/{coverband/reporters/html_test.rb → unit/reports_html_test.rb} +1 -1
- data/test/{coverband/reporters/web_test.rb → unit/reports_web_test.rb} +2 -2
- data/test/{coverband/integrations → unit}/resque_worker_test.rb +8 -9
- data/test/{coverband/integrations → unit}/test_resque_job.rb +0 -0
- data/test/unit/utils/file_groups_test.rb +31 -0
- data/test/{coverband → unit}/utils/file_list_test.rb +0 -0
- data/test/{coverband → unit}/utils/gem_list_test.rb +0 -0
- data/test/{coverband → unit}/utils/lines_classifier_test.rb +0 -0
- data/test/{coverband → unit}/utils/result_test.rb +0 -0
- data/test/{coverband → unit}/utils/s3_report_test.rb +0 -0
- data/test/{coverband → unit}/utils/source_file_line_test.rb +0 -0
- data/test/{coverband → unit}/utils/source_file_test.rb +0 -0
- data/views/layout.erb +0 -4
- metadata +61 -100
- data/lib/coverband/utils/file_path_helper.rb +0 -57
- data/public/favicon.png +0 -0
- data/test/benchmarks/coverage_fork.sh +0 -37
- data/test/coverband/collectors/coverage_test.rb +0 -67
- data/test/coverband/reporters/base_test.rb +0 -168
- data/test/coverband/utils/file_groups_test.rb +0 -55
- data/test/rails4_dummy/tmp/.keep +0 -0
- data/test/unique_files.rb +0 -23
- data/views/settings.erb +0 -35
@@ -5,7 +5,6 @@ module Coverband
|
|
5
5
|
@semaphore = Mutex.new
|
6
6
|
|
7
7
|
def self.stop
|
8
|
-
return unless @thread
|
9
8
|
@semaphore.synchronize do
|
10
9
|
if @thread
|
11
10
|
@thread.exit
|
@@ -14,10 +13,6 @@ module Coverband
|
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
|
-
def self.running?
|
18
|
-
!!@thread
|
19
|
-
end
|
20
|
-
|
21
16
|
def self.start
|
22
17
|
return if @thread
|
23
18
|
|
@@ -28,7 +23,7 @@ module Coverband
|
|
28
23
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds
|
29
24
|
@thread = Thread.new do
|
30
25
|
loop do
|
31
|
-
Coverband.report_coverage(true)
|
26
|
+
Coverband::Collectors::Coverage.instance.report_coverage(true)
|
32
27
|
logger&.debug("Coverband: Reported coverage via thread. Sleeping #{sleep_seconds}s") if Coverband.configuration.verbose
|
33
28
|
sleep(sleep_seconds)
|
34
29
|
end
|
@@ -4,20 +4,15 @@ Resque.after_fork do |job|
|
|
4
4
|
Coverband.start
|
5
5
|
end
|
6
6
|
|
7
|
-
Resque.before_first_fork do
|
8
|
-
Coverband.configuration.background_reporting_enabled = false
|
9
|
-
Coverband::Background.stop
|
10
|
-
Coverband::Collectors::Coverage.instance.report_coverage(true)
|
11
|
-
end
|
12
|
-
|
13
7
|
module Coverband
|
14
8
|
module ResqueWorker
|
15
9
|
def perform
|
16
10
|
super
|
17
11
|
ensure
|
18
|
-
Coverband.report_coverage(true)
|
12
|
+
Coverband::Collectors::Coverage.instance.report_coverage(true)
|
19
13
|
end
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
23
17
|
Resque::Job.prepend(Coverband::ResqueWorker)
|
18
|
+
|
@@ -8,10 +8,8 @@ module Coverband
|
|
8
8
|
###
|
9
9
|
class Base
|
10
10
|
class << self
|
11
|
-
include Coverband::Utils::FilePathHelper
|
12
11
|
def report(store, _options = {})
|
13
|
-
|
14
|
-
scov_style_report = get_current_scov_data_imp(store, all_roots)
|
12
|
+
scov_style_report = get_current_scov_data_imp(store, root_paths)
|
15
13
|
|
16
14
|
if Coverband.configuration.verbose
|
17
15
|
msg = "report:\n #{scov_style_report.inspect}"
|
@@ -22,6 +20,17 @@ module Coverband
|
|
22
20
|
|
23
21
|
protected
|
24
22
|
|
23
|
+
def root_paths
|
24
|
+
roots = Coverband.configuration.root_paths
|
25
|
+
roots += Coverband.configuration.gem_paths if Coverband.configuration.track_gems
|
26
|
+
roots << "#{current_root}/"
|
27
|
+
roots
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_root
|
31
|
+
File.expand_path(Coverband.configuration.root)
|
32
|
+
end
|
33
|
+
|
25
34
|
def fix_file_names(report_hash, roots)
|
26
35
|
if Coverband.configuration.verbose
|
27
36
|
Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}"
|
@@ -29,11 +38,9 @@ module Coverband
|
|
29
38
|
|
30
39
|
# normalize names across servers
|
31
40
|
report_hash.each_with_object({}) do |(key, vals), fixed_report|
|
32
|
-
filename =
|
33
|
-
fixed_report[filename] = if fixed_report.key?(filename)
|
34
|
-
|
35
|
-
vals['data'] = merged_data
|
36
|
-
vals
|
41
|
+
filename = filename_from_key(key, roots)
|
42
|
+
fixed_report[filename] = if fixed_report.key?(filename)
|
43
|
+
merge_arrays(fixed_report[filename], vals)
|
37
44
|
else
|
38
45
|
vals
|
39
46
|
end
|
@@ -55,10 +62,33 @@ module Coverband
|
|
55
62
|
merged
|
56
63
|
end
|
57
64
|
|
65
|
+
###
|
66
|
+
# This method is responsible for finding the CURRENT LOCAL
|
67
|
+
# filename regardless of the paths being different on
|
68
|
+
# various servers or deployments
|
69
|
+
###
|
70
|
+
def filename_from_key(key, roots)
|
71
|
+
relative_filename = key
|
72
|
+
local_filename = relative_filename
|
73
|
+
roots.each do |root|
|
74
|
+
relative_filename = relative_filename.gsub(/^#{root}/, './')
|
75
|
+
end
|
76
|
+
# the filename for our reports is expected to be a full path.
|
77
|
+
# roots.last should be roots << current_root}/
|
78
|
+
# a fully expanded path of config.root
|
79
|
+
# filename = filename.gsub('./', roots.last)
|
80
|
+
# above only works for app files
|
81
|
+
# we need to rethink some of this logic
|
82
|
+
# gems aren't at project root and can have multiple locations
|
83
|
+
local_root = roots.find { |root| File.exist?(relative_filename.gsub('./', root)) }
|
84
|
+
local_root ? relative_filename.gsub('./', local_root) : local_filename
|
85
|
+
end
|
86
|
+
|
58
87
|
###
|
59
88
|
# why do we need to merge covered files data?
|
60
89
|
# basically because paths on machines or deployed hosts could be different, so
|
61
90
|
# two different keys could point to the same filename or `line_key`
|
91
|
+
# this logic should be pushed to base report
|
62
92
|
# TODO: think we are filtering based on ignore while sending to the store
|
63
93
|
# and as we also pull it out here
|
64
94
|
###
|
@@ -11,7 +11,7 @@ module Coverband
|
|
11
11
|
base_path = options.fetch(:base_path) { nil }
|
12
12
|
|
13
13
|
# list all files, even if not tracked by Coverband (0% coverage)
|
14
|
-
tracked_glob = "#{
|
14
|
+
tracked_glob = "#{current_root}/{app,lib,config}/**/*.{rb}"
|
15
15
|
report_files = Coverband::Utils::Result.add_not_loaded_files(scov_style_report, tracked_glob)
|
16
16
|
# apply coverband filters
|
17
17
|
filtered_report_files = {}
|
@@ -35,10 +35,6 @@ module Coverband
|
|
35
35
|
case request.path_info
|
36
36
|
when /.*\.(css|js|gif|png)/
|
37
37
|
@static.call(env)
|
38
|
-
when %r{\/settings}
|
39
|
-
[200, { 'Content-Type' => 'text/html' }, [settings]]
|
40
|
-
when %r{\/debug_data}
|
41
|
-
[200, { 'Content-Type' => 'text/json' }, [debug_data]]
|
42
38
|
when %r{\/$}
|
43
39
|
[200, { 'Content-Type' => 'text/html' }, [index]]
|
44
40
|
else
|
@@ -57,16 +53,8 @@ module Coverband
|
|
57
53
|
open_report: false)
|
58
54
|
end
|
59
55
|
|
60
|
-
def settings
|
61
|
-
Coverband::Utils::HTMLFormatter.new(nil, base_path: base_path).format_settings!
|
62
|
-
end
|
63
|
-
|
64
|
-
def debug_data
|
65
|
-
Coverband.configuration.store.coverage.to_json
|
66
|
-
end
|
67
|
-
|
68
56
|
def collect_coverage
|
69
|
-
Coverband.report_coverage(true)
|
57
|
+
Coverband::Collectors::Coverage.instance.report_coverage(true)
|
70
58
|
notice = 'coverband coverage collected'
|
71
59
|
[301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
|
72
60
|
end
|
@@ -8,8 +8,7 @@ module Coverband
|
|
8
8
|
class FileGroups
|
9
9
|
def initialize(files)
|
10
10
|
@grouped = {}
|
11
|
-
|
12
|
-
filter_to_groups
|
11
|
+
filter_to_groups(files)
|
13
12
|
end
|
14
13
|
|
15
14
|
def grouped_results
|
@@ -18,36 +17,29 @@ module Coverband
|
|
18
17
|
|
19
18
|
private
|
20
19
|
|
21
|
-
def filter_to_groups
|
20
|
+
def filter_to_groups(files)
|
22
21
|
grouped_files = []
|
22
|
+
grouped_gems = {}
|
23
|
+
gem_lists = []
|
23
24
|
Coverband.configuration.groups.each do |name, filter|
|
24
25
|
if name == 'Gems'
|
25
|
-
|
26
|
-
|
26
|
+
grouped_gems = files.select { |source_file| source_file.filename =~ /#{filter}/ }.group_by(&:gem_name)
|
27
|
+
gem_lists = grouped_gems.values.map { |gem_files| Coverband::Utils::FileList.new(gem_files) }
|
28
|
+
grouped_files.concat(gem_lists.flatten)
|
29
|
+
@grouped[name] = Coverband::Utils::GemList.new(gem_lists) if gem_lists.flatten.any?
|
27
30
|
else
|
28
|
-
|
31
|
+
@grouped[name] = Coverband::Utils::FileList.new(files.select do |source_file|
|
32
|
+
source_file.filename =~ /#{filter}/
|
33
|
+
end)
|
29
34
|
grouped_files += @grouped[name]
|
30
35
|
end
|
31
36
|
end
|
32
|
-
if !Coverband.configuration.groups.empty? && !(other_files =
|
37
|
+
if !Coverband.configuration.groups.empty? && !(other_files = files.reject do |source_file|
|
33
38
|
grouped_files.include?(source_file)
|
34
39
|
end).empty?
|
35
40
|
@grouped['Ungrouped'] = Coverband::Utils::FileList.new(other_files)
|
36
41
|
end
|
37
42
|
end
|
38
|
-
|
39
|
-
def gem_files(name, filter)
|
40
|
-
grouped_gems = @files.select { |source_file| source_file.filename =~ /#{filter}/ }.group_by(&:gem_name)
|
41
|
-
gem_lists = grouped_gems.values.map { |gem_files| Coverband::Utils::FileList.new(gem_files) }
|
42
|
-
@grouped[name] = Coverband::Utils::GemList.new(gem_lists) if gem_lists.flatten.any?
|
43
|
-
gem_lists
|
44
|
-
end
|
45
|
-
|
46
|
-
def app_files(name, filter)
|
47
|
-
@grouped[name] = Coverband::Utils::FileList.new(@files.select do |source_file|
|
48
|
-
source_file.filename =~ /#{filter}/ && source_file.filename !~ /#{Coverband.configuration.gem_paths.first}/
|
49
|
-
end)
|
50
|
-
end
|
51
43
|
end
|
52
44
|
end
|
53
45
|
end
|
@@ -18,7 +18,7 @@ module Coverband
|
|
18
18
|
def initialize(report, options = {})
|
19
19
|
@notice = options.fetch(:notice) { nil }
|
20
20
|
@base_path = options.fetch(:base_path) { nil }
|
21
|
-
@coverage_result = Coverband::Utils::Result.new(report)
|
21
|
+
@coverage_result = Coverband::Utils::Result.new(report)
|
22
22
|
end
|
23
23
|
|
24
24
|
def format!
|
@@ -29,16 +29,8 @@ module Coverband
|
|
29
29
|
format_html(@coverage_result)
|
30
30
|
end
|
31
31
|
|
32
|
-
def format_settings!
|
33
|
-
format_settings
|
34
|
-
end
|
35
|
-
|
36
32
|
private
|
37
33
|
|
38
|
-
def format_settings
|
39
|
-
template('settings').result(binding)
|
40
|
-
end
|
41
|
-
|
42
34
|
def format(result)
|
43
35
|
Dir[File.join(File.dirname(__FILE__), '../../../public/*')].each do |path|
|
44
36
|
FileUtils.cp_r(path, asset_output_path)
|
@@ -25,13 +25,4 @@ namespace :coverband do
|
|
25
25
|
environment
|
26
26
|
Coverband.configuration.store.clear!
|
27
27
|
end
|
28
|
-
|
29
|
-
###
|
30
|
-
# clear data helpful for development or after configuration issues
|
31
|
-
###
|
32
|
-
desc 'upgrade previous Coverband datastore to latest format'
|
33
|
-
task :migrate do
|
34
|
-
environment
|
35
|
-
Coverband.configuration.store.migrate!
|
36
|
-
end
|
37
28
|
end
|
data/lib/coverband/version.rb
CHANGED
@@ -134,7 +134,7 @@ namespace :benchmarks do
|
|
134
134
|
x.config(time: 12, warmup: 5, suite: suite)
|
135
135
|
x.report 'coverband' do
|
136
136
|
work
|
137
|
-
Coverband.report_coverage
|
137
|
+
Coverband::Collectors::Coverage.instance.report_coverage
|
138
138
|
end
|
139
139
|
x.report 'no coverband' do
|
140
140
|
work
|
@@ -176,10 +176,6 @@ namespace :benchmarks do
|
|
176
176
|
@file_hash_cache[file] = Digest::MD5.file(__FILE__).hexdigest
|
177
177
|
end
|
178
178
|
end
|
179
|
-
|
180
|
-
def store.full_path_to_relative(file)
|
181
|
-
file
|
182
|
-
end
|
183
179
|
end
|
184
180
|
|
185
181
|
def reporting_speed
|
@@ -219,43 +215,12 @@ namespace :benchmarks do
|
|
219
215
|
$stdout = previous_out
|
220
216
|
end
|
221
217
|
|
222
|
-
def measure_configure_memory
|
223
|
-
require 'memory_profiler'
|
224
|
-
# warmup
|
225
|
-
3.times { Coverband.configure }
|
226
|
-
|
227
|
-
previous_out = $stdout
|
228
|
-
capture = StringIO.new
|
229
|
-
$stdout = capture
|
230
|
-
|
231
|
-
MemoryProfiler.report do
|
232
|
-
10.times do
|
233
|
-
Coverband.configure do |config|
|
234
|
-
redis_url = ENV['CACHE_REDIS_URL'] || ENV['REDIS_URL']
|
235
|
-
config.store = Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_namespace: 'coverband_data')
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end.pretty_print
|
239
|
-
data = $stdout.string
|
240
|
-
$stdout = previous_out
|
241
|
-
puts data
|
242
|
-
raise 'leaking memory!!!' unless data.match('Total retained: 0 bytes')
|
243
|
-
ensure
|
244
|
-
$stdout = previous_out
|
245
|
-
end
|
246
|
-
|
247
218
|
desc 'runs memory reporting on Redis store'
|
248
219
|
task memory_reporting: [:setup] do
|
249
220
|
puts 'runs memory benchmarking to ensure we dont leak'
|
250
221
|
measure_memory
|
251
222
|
end
|
252
223
|
|
253
|
-
desc 'runs memory reporting on configure'
|
254
|
-
task memory_configure_reporting: [:setup] do
|
255
|
-
puts 'runs memory benchmarking on configure to ensure we dont leak'
|
256
|
-
measure_configure_memory
|
257
|
-
end
|
258
|
-
|
259
224
|
desc 'runs memory leak check via Rails tests'
|
260
225
|
task memory_rails: [:setup] do
|
261
226
|
puts 'runs memory rails test to ensure we dont leak'
|
data/test/test_helper.rb
CHANGED
@@ -16,7 +16,6 @@ require 'json'
|
|
16
16
|
require 'redis'
|
17
17
|
require 'resque'
|
18
18
|
require 'pry-byebug'
|
19
|
-
require_relative 'unique_files'
|
20
19
|
$VERBOSE = original_verbosity
|
21
20
|
|
22
21
|
Coveralls.wear!
|
@@ -80,12 +79,20 @@ def basic_coverage
|
|
80
79
|
{ 'app_path/dog.rb' => example_line }
|
81
80
|
end
|
82
81
|
|
83
|
-
def
|
84
|
-
|
82
|
+
def fake_redis
|
83
|
+
@redis ||= begin
|
84
|
+
redis = OpenStruct.new
|
85
|
+
redis
|
86
|
+
end
|
85
87
|
end
|
86
88
|
|
87
|
-
def
|
88
|
-
|
89
|
+
def fake_coverage_report
|
90
|
+
file_name = '/Users/danmayer/projects/hearno/script/tester.rb'
|
91
|
+
{ file_name => [1, nil, 1, 1, nil, nil, nil] }
|
92
|
+
end
|
93
|
+
|
94
|
+
def source_fixture(filename)
|
95
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', filename))
|
89
96
|
end
|
90
97
|
|
91
98
|
# Taken from http://stackoverflow.com/questions/4459330/how-do-i-temporarily-redirect-stderr-in-ruby
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('
|
3
|
+
require File.expand_path('../test_helper', File.dirname(__FILE__))
|
4
4
|
|
5
5
|
class RedisTest < Minitest::Test
|
6
6
|
REDIS_STORAGE_FORMAT_VERSION = Coverband::Adapters::RedisStore::REDIS_STORAGE_FORMAT_VERSION
|
File without changes
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path('../test_helper', File.dirname(__FILE__))
|
4
|
+
require File.expand_path('./dog', File.dirname(__FILE__))
|
5
|
+
|
6
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
|
7
|
+
class CollectorsCoverageTest < Minitest::Test
|
8
|
+
attr_accessor :coverband
|
9
|
+
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
Coverband.configure do |config|
|
13
|
+
config.store = Coverband::Adapters::RedisStore.new(Redis.new)
|
14
|
+
end
|
15
|
+
@coverband = Coverband::Collectors::Coverage.instance.reset_instance
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
Thread.current[:coverband_instance] = nil
|
20
|
+
Coverband.configure do |config|
|
21
|
+
end
|
22
|
+
@coverband = Coverband::Collectors::Coverage.instance.reset_instance
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'gets coverage instance' do
|
26
|
+
assert_equal Coverband::Collectors::Coverage, coverband.class
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'defaults to a redis store' do
|
30
|
+
assert_equal Coverband::Adapters::RedisStore, coverband.instance_variable_get('@store').class
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'report_coverage raises errors in tests' do
|
34
|
+
@coverband.reset_instance
|
35
|
+
@coverband.expects(:ready_to_report?).raises('Oh no')
|
36
|
+
assert_raises RuntimeError do
|
37
|
+
@coverband.report_coverage
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'report_coverage does not raise errors in non-test mode' do
|
42
|
+
Coverband.configuration.stubs(:test_env).returns(false)
|
43
|
+
@coverband.expects(:ready_to_report?).raises('Oh no')
|
44
|
+
@coverband.reset_instance
|
45
|
+
@coverband.report_coverage
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|