coverband 5.1.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/diagram.yml +16 -0
- data/.github/workflows/main.yml +5 -5
- data/README.md +7 -1
- data/changes.md +15 -56
- data/coverband.gemspec +10 -0
- data/diagram.svg +1 -0
- data/lib/coverband/adapters/base.rb +8 -7
- data/lib/coverband/adapters/file_store.rb +1 -1
- data/lib/coverband/adapters/hash_redis_store.rb +1 -1
- data/lib/coverband/adapters/null_store.rb +42 -0
- data/lib/coverband/adapters/redis_store.rb +1 -1
- data/lib/coverband/collectors/coverage.rb +19 -1
- data/lib/coverband/collectors/view_tracker.rb +27 -20
- data/lib/coverband/collectors/view_tracker_service.rb +3 -3
- data/lib/coverband/configuration.rb +11 -2
- data/lib/coverband/integrations/background.rb +6 -3
- data/lib/coverband/reporters/base.rb +1 -1
- data/lib/coverband/reporters/web.rb +4 -4
- data/lib/coverband/utils/railtie.rb +3 -2
- data/lib/coverband/utils/result.rb +1 -1
- data/lib/coverband/utils/source_file.rb +2 -2
- data/lib/coverband/version.rb +2 -2
- data/lib/coverband.rb +1 -0
- data/public/dependencies.js +4 -4
- data/roadmap.md +56 -0
- data/test/coverband/adapters/null_store_test.rb +39 -0
- data/test/coverband/configuration_test.rb +5 -5
- data/test/forked/rails_full_stack_test.rb +1 -1
- data/test/integration/full_stack_deferred_eager_test.rb +51 -0
- data/test/unique_files.rb +3 -3
- data/views/file_list.erb +2 -2
- metadata +20 -7
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Coverband
|
4
|
+
module Adapters
|
5
|
+
###
|
6
|
+
# NullStore is for benchmarking the impacts of calculating
|
7
|
+
# and storing coverage data independent of Coverband/Coverage
|
8
|
+
#
|
9
|
+
# Usage:
|
10
|
+
# config.store = Coverband::Adapters::NullStore.new
|
11
|
+
###
|
12
|
+
class NullStore < Base
|
13
|
+
def initialize(_opts = {})
|
14
|
+
super()
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear!
|
18
|
+
# NOOP
|
19
|
+
end
|
20
|
+
|
21
|
+
def size
|
22
|
+
0
|
23
|
+
end
|
24
|
+
|
25
|
+
def migrate!
|
26
|
+
raise NotImplementedError, "NullStore doesn't support migrations"
|
27
|
+
end
|
28
|
+
|
29
|
+
def coverage(_local_type = nil)
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
|
33
|
+
def save_report(report)
|
34
|
+
# NOOP
|
35
|
+
end
|
36
|
+
|
37
|
+
def raw_store
|
38
|
+
raise NotImplementedError, "NullStore doesn't support raw_store"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -7,7 +7,7 @@ module Coverband
|
|
7
7
|
###
|
8
8
|
class RedisStore < Base
|
9
9
|
###
|
10
|
-
# This key isn't related to the coverband version, but to the
|
10
|
+
# This key isn't related to the coverband version, but to the internal format
|
11
11
|
# used to store data to redis. It is changed only when breaking changes to our
|
12
12
|
# redis format are required.
|
13
13
|
###
|
@@ -46,12 +46,30 @@ module Coverband
|
|
46
46
|
@store.type = old_coverage_type
|
47
47
|
end
|
48
48
|
|
49
|
+
def toggle_eager_loading
|
50
|
+
old_coverage_type = @store.type
|
51
|
+
eager_loading!
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
@store.type = old_coverage_type
|
55
|
+
end
|
56
|
+
|
49
57
|
def report_coverage
|
50
58
|
@semaphore.synchronize do
|
51
59
|
raise "no Coverband store set" unless @store
|
52
60
|
|
53
61
|
files_with_line_usage = filtered_files(Delta.results)
|
54
|
-
@store.
|
62
|
+
if @store.type == Coverband::EAGER_TYPE && Coverband.configuration.defer_eager_loading_data?
|
63
|
+
@deferred_eager_loading_data = files_with_line_usage
|
64
|
+
else
|
65
|
+
if @deferred_eager_loading_data && Coverband.configuration.defer_eager_loading_data?
|
66
|
+
toggle_eager_loading do
|
67
|
+
@store.save_report(@deferred_eager_loading_data)
|
68
|
+
@deferred_eager_loading_data = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@store.save_report(files_with_line_usage)
|
72
|
+
end
|
55
73
|
end
|
56
74
|
rescue => e
|
57
75
|
@logger&.error "coverage failed to store"
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set"
|
3
4
|
require "singleton"
|
4
5
|
|
5
6
|
module Coverband
|
@@ -12,7 +13,7 @@ module Coverband
|
|
12
13
|
# https://github.com/livingsocial/flatfoot
|
13
14
|
###
|
14
15
|
class ViewTracker
|
15
|
-
attr_accessor :target
|
16
|
+
attr_accessor :target
|
16
17
|
attr_reader :logger, :roots, :store, :ignore_patterns
|
17
18
|
|
18
19
|
def initialize(options = {})
|
@@ -29,8 +30,16 @@ module Coverband
|
|
29
30
|
@roots = @roots.split(",") if @roots.is_a?(String)
|
30
31
|
@one_time_timestamp = false
|
31
32
|
|
32
|
-
@logged_views =
|
33
|
-
@views_to_record =
|
33
|
+
@logged_views = Set.new
|
34
|
+
@views_to_record = Set.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def logged_views
|
38
|
+
@logged_views.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def views_to_record
|
42
|
+
@views_to_record.to_a
|
34
43
|
end
|
35
44
|
|
36
45
|
###
|
@@ -40,8 +49,8 @@ module Coverband
|
|
40
49
|
def track_views(_name, _start, _finish, _id, payload)
|
41
50
|
if (file = payload[:identifier])
|
42
51
|
if newly_seen_file?(file)
|
43
|
-
logged_views << file
|
44
|
-
views_to_record << file if track_file?(file)
|
52
|
+
@logged_views << file
|
53
|
+
@views_to_record << file if track_file?(file)
|
45
54
|
end
|
46
55
|
end
|
47
56
|
|
@@ -54,8 +63,8 @@ module Coverband
|
|
54
63
|
return unless (layout_file = payload[:layout])
|
55
64
|
return unless newly_seen_file?(layout_file)
|
56
65
|
|
57
|
-
logged_views << layout_file
|
58
|
-
views_to_record << layout_file if track_file?(layout_file, layout: true)
|
66
|
+
@logged_views << layout_file
|
67
|
+
@views_to_record << layout_file if track_file?(layout_file, layout: true)
|
59
68
|
end
|
60
69
|
|
61
70
|
def used_views
|
@@ -81,16 +90,17 @@ module Coverband
|
|
81
90
|
all_views.uniq
|
82
91
|
end
|
83
92
|
|
84
|
-
def unused_views
|
85
|
-
recently_used_views = used_views.keys
|
86
|
-
unused_views = all_views
|
93
|
+
def unused_views(used_views = nil)
|
94
|
+
recently_used_views = (used_views || self.used_views).keys
|
95
|
+
unused_views = all_views - recently_used_views
|
87
96
|
# since layouts don't include format we count them used if they match with ANY formats
|
88
97
|
unused_views.reject { |view| view.match(/\/layouts\//) && recently_used_views.any? { |used_view| view.include?(used_view) } }
|
89
98
|
end
|
90
99
|
|
91
100
|
def as_json
|
101
|
+
used_views = self.used_views
|
92
102
|
{
|
93
|
-
unused_views: unused_views,
|
103
|
+
unused_views: unused_views(used_views),
|
94
104
|
used_views: used_views
|
95
105
|
}.to_json
|
96
106
|
end
|
@@ -113,17 +123,17 @@ module Coverband
|
|
113
123
|
|
114
124
|
filename = "#{@project_directory}/#{filename}"
|
115
125
|
redis_store.hdel(tracker_key, filename)
|
116
|
-
logged_views.delete(filename)
|
126
|
+
@logged_views.delete(filename)
|
117
127
|
end
|
118
128
|
|
119
129
|
def report_views_tracked
|
120
130
|
redis_store.set(tracker_time_key, Time.now.to_i) unless @one_time_timestamp || tracker_time_key_exists?
|
121
131
|
@one_time_timestamp = true
|
122
132
|
reported_time = Time.now.to_i
|
123
|
-
views_to_record.each do |file|
|
133
|
+
@views_to_record.each do |file|
|
124
134
|
redis_store.hset(tracker_key, file, reported_time)
|
125
135
|
end
|
126
|
-
|
136
|
+
@views_to_record.clear
|
127
137
|
rescue => e
|
128
138
|
# we don't want to raise errors if Coverband can't reach redis.
|
129
139
|
# This is a nice to have not a bring the system down
|
@@ -137,15 +147,12 @@ module Coverband
|
|
137
147
|
protected
|
138
148
|
|
139
149
|
def newly_seen_file?(file)
|
140
|
-
|
141
|
-
|
142
|
-
true
|
150
|
+
!@logged_views.include?(file)
|
143
151
|
end
|
144
152
|
|
145
153
|
def track_file?(file, options = {})
|
146
|
-
|
147
|
-
file.include?(pattern)
|
148
|
-
end && (file.start_with?(@project_directory) || options[:layout])
|
154
|
+
(file.start_with?(@project_directory) || options[:layout]) &&
|
155
|
+
@ignore_patterns.none? { |pattern| file.include?(pattern) }
|
149
156
|
end
|
150
157
|
|
151
158
|
private
|
@@ -8,8 +8,8 @@ module Coverband
|
|
8
8
|
class ViewTrackerService < ViewTracker
|
9
9
|
def report_views_tracked
|
10
10
|
reported_time = Time.now.to_i
|
11
|
-
if views_to_record.any?
|
12
|
-
relative_views = views_to_record.map! do |view|
|
11
|
+
if @views_to_record.any?
|
12
|
+
relative_views = @views_to_record.map! do |view|
|
13
13
|
roots.each do |root|
|
14
14
|
view = view.gsub(/#{root}/, "")
|
15
15
|
end
|
@@ -17,7 +17,7 @@ module Coverband
|
|
17
17
|
end
|
18
18
|
save_tracked_views(views: relative_views, reported_time: reported_time)
|
19
19
|
end
|
20
|
-
|
20
|
+
@views_to_record = []
|
21
21
|
rescue => e
|
22
22
|
# we don't want to raise errors if Coverband can't reach the service
|
23
23
|
logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
|
@@ -8,7 +8,7 @@ module Coverband
|
|
8
8
|
:background_reporting_enabled,
|
9
9
|
:test_env, :web_enable_clear, :gem_details, :web_debug, :report_on_exit,
|
10
10
|
:simulate_oneshot_lines_coverage,
|
11
|
-
:view_tracker
|
11
|
+
:view_tracker, :defer_eager_loading_data
|
12
12
|
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
|
13
13
|
:s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
|
14
14
|
:service_test_mode, :process_type, :track_views, :redis_url,
|
@@ -62,6 +62,7 @@ module Coverband
|
|
62
62
|
@store = nil
|
63
63
|
@background_reporting_enabled = true
|
64
64
|
@background_reporting_sleep_seconds = nil
|
65
|
+
@defer_eager_loading_data = false
|
65
66
|
@test_env = nil
|
66
67
|
@web_enable_clear = false
|
67
68
|
@track_views = true
|
@@ -147,7 +148,9 @@ module Coverband
|
|
147
148
|
end
|
148
149
|
|
149
150
|
def track_views
|
150
|
-
|
151
|
+
return false if service_disabled_dev_test_env?
|
152
|
+
|
153
|
+
@track_views
|
151
154
|
end
|
152
155
|
|
153
156
|
###
|
@@ -241,7 +244,13 @@ module Coverband
|
|
241
244
|
Coverband.coverband_service? || !api_key.nil?
|
242
245
|
end
|
243
246
|
|
247
|
+
def defer_eager_loading_data?
|
248
|
+
@defer_eager_loading_data
|
249
|
+
end
|
250
|
+
|
244
251
|
def service_disabled_dev_test_env?
|
252
|
+
return false unless service?
|
253
|
+
|
245
254
|
(coverband_env == "test" && !Coverband.configuration.service_test_mode) ||
|
246
255
|
(coverband_env == "development" && !Coverband.configuration.service_dev_mode)
|
247
256
|
end
|
@@ -31,15 +31,18 @@ module Coverband
|
|
31
31
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
|
32
32
|
@thread = Thread.new {
|
33
33
|
loop do
|
34
|
-
Coverband.report_coverage
|
35
|
-
Coverband.configuration.view_tracker&.report_views_tracked
|
36
34
|
if Coverband.configuration.reporting_wiggle
|
37
35
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i + rand(Coverband.configuration.reporting_wiggle.to_i)
|
38
36
|
end
|
37
|
+
# NOTE: Normally as processes first start we immediately report, this causes a redis spike on deploys
|
38
|
+
# if deferred is set also sleep frst to spread load
|
39
|
+
sleep(sleep_seconds.to_i) if Coverband.configuration.defer_eager_loading_data?
|
40
|
+
Coverband.report_coverage
|
41
|
+
Coverband.configuration.view_tracker&.report_views_tracked
|
39
42
|
if Coverband.configuration.verbose
|
40
43
|
logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
|
41
44
|
end
|
42
|
-
sleep(sleep_seconds.to_i)
|
45
|
+
sleep(sleep_seconds.to_i) unless Coverband.configuration.defer_eager_loading_data?
|
43
46
|
end
|
44
47
|
}
|
45
48
|
end
|
@@ -15,7 +15,7 @@ module Coverband
|
|
15
15
|
scov_style_report = get_current_scov_data_imp(store, all_roots)
|
16
16
|
|
17
17
|
# These are extremelhy verbose but useful during coverband development, not generally for users
|
18
|
-
# Only
|
18
|
+
# Only available by uncommenting this mode is never released
|
19
19
|
# if Coverband.configuration.verbose
|
20
20
|
# # msg = "report:\n #{scov_style_report.inspect}"
|
21
21
|
# # Coverband.configuration.logger.debug msg
|
@@ -124,7 +124,7 @@ module Coverband
|
|
124
124
|
Coverband.configuration.store.clear!
|
125
125
|
notice = "coverband coverage cleared"
|
126
126
|
else
|
127
|
-
notice = "web_enable_clear
|
127
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
128
128
|
end
|
129
129
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
130
130
|
end
|
@@ -135,7 +135,7 @@ module Coverband
|
|
135
135
|
Coverband.configuration.store.clear_file!(filename)
|
136
136
|
notice = "coverage for file #{filename} cleared"
|
137
137
|
else
|
138
|
-
notice = "web_enable_clear
|
138
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
139
139
|
end
|
140
140
|
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
|
141
141
|
end
|
@@ -146,7 +146,7 @@ module Coverband
|
|
146
146
|
tracker.reset_recordings
|
147
147
|
notice = "view tracking reset"
|
148
148
|
else
|
149
|
-
notice = "web_enable_clear
|
149
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
150
150
|
end
|
151
151
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
152
152
|
end
|
@@ -158,7 +158,7 @@ module Coverband
|
|
158
158
|
tracker.clear_file!(filename)
|
159
159
|
notice = "coverage for file #{filename} cleared"
|
160
160
|
else
|
161
|
-
notice = "web_enable_clear
|
161
|
+
notice = "web_enable_clear isn't enabled in your configuration"
|
162
162
|
end
|
163
163
|
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
|
164
164
|
end
|
@@ -21,7 +21,7 @@ module Coverband
|
|
21
21
|
|
22
22
|
config.after_initialize do
|
23
23
|
unless Coverband.tasks_to_ignore?
|
24
|
-
Coverband.configure
|
24
|
+
Coverband.configure unless Coverband.configured?
|
25
25
|
Coverband.eager_loading_coverage!
|
26
26
|
Coverband.report_coverage
|
27
27
|
Coverband.runtime_coverage!
|
@@ -37,7 +37,7 @@ module Coverband
|
|
37
37
|
|
38
38
|
Coverband.configuration.view_tracker = COVERBAND_VIEW_TRACKER
|
39
39
|
|
40
|
-
ActiveSupport::Notifications.subscribe(/
|
40
|
+
ActiveSupport::Notifications.subscribe(/render_(template|partial|collection).action_view/) do |name, start, finish, id, payload|
|
41
41
|
COVERBAND_VIEW_TRACKER.track_views(name, start, finish, id, payload) unless name.include?("!")
|
42
42
|
end
|
43
43
|
end
|
@@ -50,6 +50,7 @@ module Coverband
|
|
50
50
|
config.before_configuration do
|
51
51
|
unless ENV["COVERBAND_DISABLE_AUTO_START"]
|
52
52
|
begin
|
53
|
+
Coverband.configure unless Coverband.configured?
|
53
54
|
Coverband.start
|
54
55
|
rescue Redis::CannotConnectError => error
|
55
56
|
Coverband.configuration.logger.info "Redis is not available (#{error}), Coverband not configured"
|
@@ -101,7 +101,7 @@ module Coverband
|
|
101
101
|
@last_updated_at = Time.at(file_data["last_updated_at"]) if file_data["last_updated_at"]
|
102
102
|
@never_loaded = file_data["never_loaded"] || false
|
103
103
|
else
|
104
|
-
# TODO: Deprecate this code path this was backwards
|
104
|
+
# TODO: Deprecate this code path this was backwards compatibility from 3-4
|
105
105
|
@coverage = file_data
|
106
106
|
@first_updated_at = NOT_AVAILABLE
|
107
107
|
@last_updated_at = NOT_AVAILABLE
|
@@ -139,7 +139,7 @@ module Coverband
|
|
139
139
|
coverage_exceeding_source_warn if coverage.size > src.size
|
140
140
|
|
141
141
|
lines = src.map.with_index(1) { |src, i|
|
142
|
-
Coverband::Utils::SourceFile::Line.new(src, i, coverage[i - 1])
|
142
|
+
Coverband::Utils::SourceFile::Line.new(src, i, never_loaded ? 0 : coverage[i - 1])
|
143
143
|
}
|
144
144
|
|
145
145
|
process_skipped_lines(lines)
|
data/lib/coverband/version.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
###
|
4
4
|
# ensure we properly do release candidate versioning; https://github.com/danmayer/coverband/issues/288
|
5
|
-
# use format
|
5
|
+
# use format "4.2.1.rc.1" ~> 4.2.1.rc to prerelease versions like v4.2.1.rc.2 and v4.2.1.rc.3
|
6
6
|
###
|
7
7
|
module Coverband
|
8
|
-
VERSION = '5.
|
8
|
+
VERSION = '5.2.0'
|
9
9
|
end
|
data/lib/coverband.rb
CHANGED
@@ -13,6 +13,7 @@ require "coverband/adapters/redis_store"
|
|
13
13
|
require "coverband/adapters/hash_redis_store"
|
14
14
|
require "coverband/adapters/file_store"
|
15
15
|
require "coverband/adapters/stdout_store"
|
16
|
+
require "coverband/adapters/null_store"
|
16
17
|
require "coverband/utils/file_hasher"
|
17
18
|
require "coverband/collectors/coverage"
|
18
19
|
require "coverband/collectors/view_tracker"
|
data/public/dependencies.js
CHANGED
@@ -103,7 +103,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
103
103
|
return this.rel;
|
104
104
|
},
|
105
105
|
href: function() {
|
106
|
-
// using this.href would give the absolute url, when the href may have been
|
106
|
+
// using this.href would give the absolute url, when the href may have been intedned as a selector (e.g. '#container')
|
107
107
|
return $(this).attr('href');
|
108
108
|
},
|
109
109
|
title: function() {
|
@@ -397,7 +397,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
397
397
|
loadedHeight = $loaded.outerHeight(true);
|
398
398
|
loadedWidth = $loaded.outerWidth(true);
|
399
399
|
|
400
|
-
// Opens
|
400
|
+
// Opens initial empty Colorbox prior to content being loaded.
|
401
401
|
var initialWidth = setSize(settings.get('initialWidth'), 'x');
|
402
402
|
var initialHeight = setSize(settings.get('initialHeight'), 'y');
|
403
403
|
var maxWidth = settings.get('maxWidth');
|
@@ -983,7 +983,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/<
|
|
983
983
|
return;
|
984
984
|
}
|
985
985
|
|
986
|
-
// A small pause because some browsers will
|
986
|
+
// A small pause because some browsers will occasionally report a
|
987
987
|
// img.width and img.height of zero immediately after the img.onload fires
|
988
988
|
setTimeout(function(){
|
989
989
|
var percent;
|
@@ -1236,7 +1236,7 @@ u;this.oApi._fnAddColumn=y;this.oApi._fnColumnOptions=C;this.oApi._fnAddData=w;t
|
|
1236
1236
|
Q;this.oApi._fnFilterCreateSearch=fa;this.oApi._fnDataToSearch=ga;this.oApi._fnSort=O;this.oApi._fnSortAttachListener=$;this.oApi._fnSortingClasses=W;this.oApi._fnFeatureHtmlPaginate=wa;this.oApi._fnPageChange=Ba;this.oApi._fnFeatureHtmlInfo=va;this.oApi._fnUpdateInfo=Ca;this.oApi._fnFeatureHtmlLength=ra;this.oApi._fnFeatureHtmlProcessing=ta;this.oApi._fnProcessingDisplay=K;this.oApi._fnVisibleToColumnIndex=da;this.oApi._fnColumnIndexToVisible=N;this.oApi._fnNodeToDataIndex=R;this.oApi._fnVisbleColumns=
|
1237
1237
|
T;this.oApi._fnCalculateEnd=F;this.oApi._fnConvertToWidth=Da;this.oApi._fnCalculateColumnWidths=ea;this.oApi._fnScrollingWidthAdjust=ia;this.oApi._fnGetWidestNode=Ea;this.oApi._fnGetMaxLenString=Fa;this.oApi._fnStringToCss=v;this.oApi._fnArrayCmp=La;this.oApi._fnDetectType=Z;this.oApi._fnSettingsFromNode=B;this.oApi._fnGetDataMaster=V;this.oApi._fnGetTrNodes=S;this.oApi._fnGetTdNodes=X;this.oApi._fnEscapeRegex=ha;this.oApi._fnDeleteIndex=ja;this.oApi._fnReOrderIndex=qa;this.oApi._fnColumnOrdering=
|
1238
1238
|
aa;this.oApi._fnLog=J;this.oApi._fnClearTable=ba;this.oApi._fnSaveState=Ga;this.oApi._fnLoadState=Ia;this.oApi._fnCreateCookie=Ha;this.oApi._fnReadCookie=ka;this.oApi._fnGetUniqueThs=ca;this.oApi._fnScrollBarWidth=Ja;this.oApi._fnApplyToChildren=M;this.oApi._fnMap=n;var Ka=this;return this.each(function(){var a=0,b,c,d,f;a=0;for(b=E.length;a<b;a++){if(E[a].nTable==this)if(typeof g=="undefined"||typeof g.bRetrieve!="undefined"&&g.bRetrieve===true)return E[a].oInstance;else if(typeof g.bDestroy!="undefined"&&
|
1239
|
-
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to
|
1239
|
+
g.bDestroy===true){E[a].oInstance.fnDestroy();break}else{J(E[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, please pass either no arguments to the dataTable() function, or set bRetrieve to true. Alternatively, to destroy the old table and create a new one, set bDestroy to true (note that a lot of changes to the configuration can be made through the API which is usually much faster).");return}if(E[a].sTableId!==""&&E[a].sTableId==this.getAttribute("id")){E.splice(a,
|
1240
1240
|
1);break}}var e=new l;E.push(e);var i=false,h=false;a=this.getAttribute("id");if(a!==null){e.sTableId=a;e.sInstance=a}else e.sInstance=m._oExternConfig.iNextUnique++;e.oInstance=Ka;e.nTable=this;e.oApi=Ka.oApi;if(typeof g!="undefined"&&g!==null){e.oInit=g;n(e.oFeatures,g,"bPaginate");n(e.oFeatures,g,"bLengthChange");n(e.oFeatures,g,"bFilter");n(e.oFeatures,g,"bSort");n(e.oFeatures,g,"bInfo");n(e.oFeatures,g,"bProcessing");n(e.oFeatures,g,"bAutoWidth");n(e.oFeatures,g,"bSortClasses");n(e.oFeatures,
|
1241
1241
|
g,"bServerSide");n(e.oScroll,g,"sScrollX","sX");n(e.oScroll,g,"sScrollXInner","sXInner");n(e.oScroll,g,"sScrollY","sY");n(e.oScroll,g,"bScrollCollapse","bCollapse");n(e,g,"asStripClasses");n(e,g,"fnRowCallback");n(e,g,"fnHeaderCallback");n(e,g,"fnFooterCallback");n(e,g,"fnInitComplete");n(e,g,"fnServerData");n(e,g,"fnFormatNumber");n(e,g,"aaSorting");n(e,g,"aaSortingFixed");n(e,g,"aLengthMenu");n(e,g,"sPaginationType");n(e,g,"sAjaxSource");n(e,g,"iCookieDuration");n(e,g,"sCookiePrefix");n(e,g,"sDom");
|
1242
1242
|
n(e,g,"oSearch","oPreviousSearch");n(e,g,"aoSearchCols","aoPreSearchCols");n(e,g,"iDisplayLength","_iDisplayLength");n(e,g,"bJQueryUI","bJUI");typeof g.fnDrawCallback=="function"&&e.aoDrawCallback.push({fn:g.fnDrawCallback,sName:"user"});e.oFeatures.bServerSide&&e.oFeatures.bSort&&e.oFeatures.bSortClasses&&e.aoDrawCallback.push({fn:W,sName:"server_side_sort_classes"});if(typeof g.bJQueryUI!="undefined"&&g.bJQueryUI){e.oClasses=m.oJUIClasses;if(typeof g.sDom=="undefined")e.sDom='<"H"lfr>t<"F"ip>'}if(e.oScroll.sX!==
|
data/roadmap.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Future Roadmap
|
2
|
+
|
3
|
+
### Research Alternative Redis formats
|
4
|
+
|
5
|
+
- Look at alternative storage formats for Redis
|
6
|
+
- [redis bitmaps](http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/)
|
7
|
+
- [redis bitfield](https://stackoverflow.com/questions/47100606/optimal-way-to-store-array-of-integers-in-redis-database)
|
8
|
+
- Add support for [zadd](http://redis.io/topics/data-types-intro) so one could determine single call versus multiple calls on a line, letting us determine the most executed code in production.
|
9
|
+
|
10
|
+
### Coverband Future...
|
11
|
+
|
12
|
+
Will be the fully modern release that drops maintenance legacy support in favor of increased performance, ease of use, and maintainability.
|
13
|
+
|
14
|
+
- Release will be aimed as significantly simplifying ease of use
|
15
|
+
- near zero config setup for Rails apps
|
16
|
+
- add built-in support for easy loading via Railties
|
17
|
+
- built in support for activejob, sidekiq, and other common frameworks
|
18
|
+
- reduced configuration options
|
19
|
+
- support oneshot
|
20
|
+
- drop middleware figure out a way to kick off background without middelware
|
21
|
+
- options on reporting
|
22
|
+
- background reporting
|
23
|
+
- or middleware reporting
|
24
|
+
- Support for file versions
|
25
|
+
- md5 or release tags
|
26
|
+
- add coverage timerange support
|
27
|
+
- Drop Simplecov dependency
|
28
|
+
- improved web reporting
|
29
|
+
- lists current config options
|
30
|
+
- eventually allow updating remote config
|
31
|
+
- full theming
|
32
|
+
- list redis data dump for debugging
|
33
|
+
- additional adapters: Memcache, S3, and ActiveRecord
|
34
|
+
- add articles / podcasts like prontos readme https://github.com/prontolabs/pronto
|
35
|
+
- Add detailed Gem usage report, if we collect and send gem usage we can give percentage of gem code used, which should help application developers know when to remove gem dependencies (0%) or perhaps inline single methods for little usage (using <= 5%) for example.
|
36
|
+
- add meta data information first seen last recorded to the coverage report views (probably need to drop simplecov for that).
|
37
|
+
- more details in this issue: https://github.com/danmayer/coverband/issues/118
|
38
|
+
- Make good video on setup, install, usage
|
39
|
+
- See if we can add support for views / templates
|
40
|
+
- using this technique https://github.com/ioquatix/covered
|
41
|
+
- Better default grouping (could use groups features for gems for rails controllers, models, lib, etc)
|
42
|
+
- Improved logging for easier debugging and development
|
43
|
+
- drop the verbose mode and better support standard logger levels
|
44
|
+
- Possibly setup a build assets system
|
45
|
+
- my JS rules expanded the compressed JS at the top of application.js, basically we want to stitch together JS
|
46
|
+
- I guess we could also load multiple JS files as most of the JS is just default compressed JS and a tiny amount of actual app JS.
|
47
|
+
- lazy load for Coverband results
|
48
|
+
- view layer file coverage
|
49
|
+
- move all code to work with relative paths leaving only stdlib Coverage working on full paths
|
50
|
+
- add gem_safe_lists to track only some gems
|
51
|
+
- add gem_details_safe list to report on details on some gems
|
52
|
+
- - display gems that are in loaded with 0 coverage, thanks @kbaum
|
53
|
+
|
54
|
+
# Alpha / Beta / Release Candidates
|
55
|
+
|
56
|
+
### Coverband 5.?.?
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("../../test_helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class AdaptersNullStoreTest < Minitest::Test
|
6
|
+
def test_covered_lines_when_no_file
|
7
|
+
@store = Coverband::Adapters::NullStore.new("")
|
8
|
+
expected = {}
|
9
|
+
assert_equal expected, @store.coverage
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Coverband::Adapters::NullStore" do
|
13
|
+
def setup
|
14
|
+
super
|
15
|
+
@store = Coverband::Adapters::NullStore.new(@test_file_path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_coverage
|
19
|
+
assert_equal @store.coverage, {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_covered_lines_when_null
|
23
|
+
assert_nil @store.coverage["none.rb"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_covered_files
|
27
|
+
assert_equal @store.covered_files.include?("dog.rb"), false
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_clear
|
31
|
+
assert_nil @store.clear!
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_save_report
|
35
|
+
@store.send(:save_report, "cat.rb" => [0, 1])
|
36
|
+
assert_equal @store.coverage, {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -10,7 +10,7 @@ class BaseTest < Minitest::Test
|
|
10
10
|
Coverband.configure do |config|
|
11
11
|
config.root = Dir.pwd
|
12
12
|
config.root_paths = ["/app_path/"]
|
13
|
-
config.ignore = ["config/
|
13
|
+
config.ignore = ["config/environments"]
|
14
14
|
config.reporter = "std_out"
|
15
15
|
config.store = Coverband::Adapters::RedisStore.new(Coverband::Test.redis, redis_namespace: "coverband_test")
|
16
16
|
end
|
@@ -18,7 +18,7 @@ class BaseTest < Minitest::Test
|
|
18
18
|
|
19
19
|
test "ignore works with equal" do
|
20
20
|
Coverband::Collectors::Coverage.instance.reset_instance
|
21
|
-
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/
|
21
|
+
expected = ["vendor/", ".erb$", ".slim$", "/tmp", "internal:prelude", "db/schema.rb", "config/environments"]
|
22
22
|
assert_equal expected, Coverband.configuration.ignore
|
23
23
|
end
|
24
24
|
|
@@ -33,7 +33,7 @@ class BaseTest < Minitest::Test
|
|
33
33
|
"/tmp",
|
34
34
|
"internal:prelude",
|
35
35
|
"db/schema.rb",
|
36
|
-
"config/
|
36
|
+
"config/environments",
|
37
37
|
"config/initializers"]
|
38
38
|
assert_equal expected, Coverband.configuration.ignore
|
39
39
|
end
|
@@ -47,7 +47,7 @@ class BaseTest < Minitest::Test
|
|
47
47
|
Coverband::Collectors::Coverage.instance.reset_instance
|
48
48
|
current_paths = Coverband.configuration.root_paths.dup
|
49
49
|
# verify previous bug fix
|
50
|
-
# it would extend the root_paths instance variable on each
|
50
|
+
# it would extend the root_paths instance variable on each invocation
|
51
51
|
Coverband.configuration.all_root_paths
|
52
52
|
Coverband.configuration.all_root_paths
|
53
53
|
assert_equal current_paths, Coverband.configuration.root_paths
|
@@ -103,7 +103,7 @@ class BaseTest < Minitest::Test
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
-
test "store
|
106
|
+
test "store doesn't raises when api key and redis_url" do
|
107
107
|
Coverband::Collectors::Coverage.instance.reset_instance
|
108
108
|
Coverband.configuration.reset
|
109
109
|
Coverband.configure do |config|
|
@@ -58,7 +58,7 @@ class RailsFullStackTest < Minitest::Test
|
|
58
58
|
|
59
59
|
# we don't want this to run during our standard test suite
|
60
60
|
# as the below profiler changes the runtime
|
61
|
-
# and
|
61
|
+
# and should only be included for isolated processes
|
62
62
|
begin
|
63
63
|
require "memory_profiler"
|
64
64
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
4
|
+
require "rack"
|
5
|
+
|
6
|
+
class FullStackDeferredEagerTest < Minitest::Test
|
7
|
+
REDIS_STORAGE_FORMAT_VERSION = Coverband::Adapters::RedisStore::REDIS_STORAGE_FORMAT_VERSION
|
8
|
+
TEST_RACK_APP = "../fake_app/basic_rack.rb"
|
9
|
+
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
Coverband::Collectors::Coverage.instance.reset_instance
|
13
|
+
Coverband.configure do |config|
|
14
|
+
config.background_reporting_enabled = false
|
15
|
+
config.track_gems = true
|
16
|
+
config.defer_eager_loading_data = true
|
17
|
+
end
|
18
|
+
Coverband.start
|
19
|
+
Coverband::Collectors::Coverage.instance.eager_loading!
|
20
|
+
@rack_file = require_unique_file "fake_app/basic_rack.rb"
|
21
|
+
Coverband.report_coverage
|
22
|
+
Coverband::Collectors::Coverage.instance.runtime!
|
23
|
+
end
|
24
|
+
|
25
|
+
test "call app" do
|
26
|
+
# eager loaded class coverage starts empty
|
27
|
+
Coverband.eager_loading_coverage!
|
28
|
+
expected = {}
|
29
|
+
assert_equal expected, Coverband.configuration.store.coverage
|
30
|
+
|
31
|
+
Coverband::Collectors::Coverage.instance.runtime!
|
32
|
+
request = Rack::MockRequest.env_for("/anything.json")
|
33
|
+
middleware = Coverband::BackgroundMiddleware.new(fake_app_with_lines)
|
34
|
+
results = middleware.call(request)
|
35
|
+
assert_equal "Hello Rack!", results.last
|
36
|
+
Coverband.report_coverage
|
37
|
+
expected = [nil, nil, 0, nil, 0, 0, 1, nil, nil]
|
38
|
+
assert_equal expected, Coverband.configuration.store.coverage[@rack_file]["data"]
|
39
|
+
|
40
|
+
# eager loaded class coverage is saved at first normal coverage report
|
41
|
+
Coverband.eager_loading_coverage!
|
42
|
+
expected = [nil, nil, 1, nil, 1, 1, 0, nil, nil]
|
43
|
+
assert_equal expected, Coverband.configuration.store.coverage[@rack_file]["data"]
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def fake_app_with_lines
|
49
|
+
@fake_app_with_lines ||= ::HelloWorld.new
|
50
|
+
end
|
51
|
+
end
|