coverband 5.2.6.rc.1 → 5.2.6.rc.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,45 +12,35 @@ module Coverband
12
12
  # but am now rolling into Coverband
13
13
  # https://github.com/livingsocial/flatfoot
14
14
  ###
15
- class ViewTracker
16
- attr_accessor :target
17
- attr_reader :logger, :roots, :store, :ignore_patterns
15
+ class ViewTracker < AbstractTracker
16
+ attr_reader :roots
18
17
 
19
- def initialize(options = {})
20
- raise NotImplementedError, "View Tracker requires Rails 4 or greater" unless self.class.supported_version?
21
- raise "Coverband: view tracker initialized before configuration!" if !Coverband.configured? && ENV["COVERBAND_TEST"] == "test"
18
+ REPORT_ROUTE = "views_tracker"
19
+ TITLE = "Views"
22
20
 
21
+ def initialize(options = {})
23
22
  @project_directory = File.expand_path(Coverband.configuration.root)
24
- @ignore_patterns = Coverband.configuration.ignore
25
- @store = options.fetch(:store) { Coverband.configuration.store }
26
- @logger = options.fetch(:logger) { Coverband.configuration.logger }
27
- @target = options.fetch(:target) { Dir.glob("#{@project_directory}/app/views/**/*.html.{erb,haml,slim}") }
28
-
29
23
  @roots = options.fetch(:roots) { Coverband.configuration.all_root_patterns }
30
24
  @roots = @roots.split(",") if @roots.is_a?(String)
31
- @one_time_timestamp = false
32
-
33
- @logged_views = Set.new
34
- @views_to_record = Set.new
35
- end
36
25
 
37
- def logged_views
38
- @logged_views.to_a
26
+ super
39
27
  end
40
28
 
41
- def views_to_record
42
- @views_to_record.to_a
29
+ def railtie!
30
+ ActiveSupport::Notifications.subscribe(/render_(template|partial|collection).action_view/) do |name, start, finish, id, payload|
31
+ Coverband.configuration.view_tracker.track_key(payload) unless name.include?("!")
32
+ end
43
33
  end
44
34
 
45
35
  ###
46
36
  # This method is called on every render call, so we try to reduce method calls
47
37
  # and ensure high performance
48
38
  ###
49
- def track_views(_name, _start, _finish, _id, payload)
39
+ def track_key(payload)
50
40
  if (file = payload[:identifier])
51
- if newly_seen_file?(file)
52
- @logged_views << file
53
- @views_to_record << file if track_file?(file)
41
+ if newly_seen_key?(file)
42
+ @logged_keys << file
43
+ @keys_to_record << file if track_file?(file)
54
44
  end
55
45
  end
56
46
 
@@ -61,13 +51,13 @@ module Coverband
61
51
  # http://edgeguides.rubyonrails.org/active_support_instrumentation.html#render_partial-action_view
62
52
  ###
63
53
  return unless (layout_file = payload[:layout])
64
- return unless newly_seen_file?(layout_file)
54
+ return unless newly_seen_key?(layout_file)
65
55
 
66
- @logged_views << layout_file
67
- @views_to_record << layout_file if track_file?(layout_file, layout: true)
56
+ @logged_keys << layout_file
57
+ @keys_to_record << layout_file if track_file?(layout_file, layout: true)
68
58
  end
69
59
 
70
- def used_views
60
+ def used_keys
71
61
  views = redis_store.hgetall(tracker_key)
72
62
  normalized_views = {}
73
63
  views.each_pair do |view, time|
@@ -79,7 +69,7 @@ module Coverband
79
69
  normalized_views
80
70
  end
81
71
 
82
- def all_views
72
+ def all_keys
83
73
  all_views = []
84
74
  target.each do |view|
85
75
  roots.each do |root|
@@ -90,92 +80,35 @@ module Coverband
90
80
  all_views.uniq
91
81
  end
92
82
 
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
83
+ def unused_keys(used_views = nil)
84
+ recently_used_views = (used_keys || used_keys).keys
85
+ unused_views = all_keys - recently_used_views
96
86
  # since layouts don't include format we count them used if they match with ANY formats
97
87
  unused_views.reject { |view| view.match(/\/layouts\//) && recently_used_views.any? { |used_view| view.include?(used_view) } }
98
88
  end
99
89
 
100
- def as_json
101
- used_views = self.used_views
102
- {
103
- unused_views: unused_views(used_views),
104
- used_views: used_views
105
- }.to_json
106
- end
107
-
108
- def tracking_since
109
- if (tracking_time = redis_store.get(tracker_time_key))
110
- Time.at(tracking_time.to_i).iso8601
111
- else
112
- "N/A"
113
- end
114
- end
115
-
116
- def reset_recordings
117
- redis_store.del(tracker_key)
118
- redis_store.del(tracker_time_key)
119
- end
120
-
121
- def clear_file!(filename)
90
+ def clear_key!(filename)
122
91
  return unless filename
123
92
 
124
93
  filename = "#{@project_directory}/#{filename}"
125
94
  redis_store.hdel(tracker_key, filename)
126
- @logged_views.delete(filename)
127
- end
128
-
129
- def report_views_tracked
130
- redis_store.set(tracker_time_key, Time.now.to_i) unless @one_time_timestamp || tracker_time_key_exists?
131
- @one_time_timestamp = true
132
- reported_time = Time.now.to_i
133
- @views_to_record.to_a.each do |file|
134
- redis_store.hset(tracker_key, file, reported_time)
135
- end
136
- @views_to_record.clear
137
- rescue => e
138
- # we don't want to raise errors if Coverband can't reach redis.
139
- # This is a nice to have not a bring the system down
140
- logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}"
141
- end
142
-
143
- def self.supported_version?
144
- defined?(Rails) && defined?(Rails::VERSION) && Rails::VERSION::STRING.split(".").first.to_i >= 4
95
+ @logged_keys.delete(filename)
145
96
  end
146
97
 
147
- protected
148
-
149
- def newly_seen_file?(file)
150
- !@logged_views.include?(file)
151
- end
98
+ private
152
99
 
153
100
  def track_file?(file, options = {})
154
101
  (file.start_with?(@project_directory) || options[:layout]) &&
155
102
  @ignore_patterns.none? { |pattern| file.include?(pattern) }
156
103
  end
157
104
 
158
- private
159
-
160
- def redis_store
161
- store.raw_store
162
- end
163
-
164
- def tracker_time_key_exists?
165
- if defined?(redis_store.exists?)
166
- redis_store.exists?(tracker_time_key)
105
+ def concrete_target
106
+ if defined?(Rails.application)
107
+ Dir.glob("#{@project_directory}/app/views/**/*.html.{erb,haml,slim}")
167
108
  else
168
- redis_store.exists(tracker_time_key)
109
+ []
169
110
  end
170
111
  end
171
-
172
- def tracker_key
173
- "render_tracker_2"
174
- end
175
-
176
- def tracker_time_key
177
- "render_tracker_time"
178
- end
179
112
  end
180
113
  end
181
114
  end
@@ -6,7 +6,7 @@ module Coverband
6
6
  # This class extends view tracker to support web service reporting
7
7
  ###
8
8
  class ViewTrackerService < ViewTracker
9
- def report_views_tracked
9
+ def save_report
10
10
  reported_time = Time.now.to_i
11
11
  if @views_to_record.any?
12
12
  relative_views = @views_to_record.map! do |view|
@@ -10,7 +10,8 @@ module Coverband
10
10
  :simulate_oneshot_lines_coverage,
11
11
  :view_tracker, :defer_eager_loading_data,
12
12
  :track_routes, :route_tracker,
13
- :track_translations, :translations_tracker
13
+ :track_translations, :translations_tracker,
14
+ :trackers
14
15
  attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
15
16
  :s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
16
17
  :service_test_mode, :process_type, :track_views, :redis_url,
@@ -95,6 +96,8 @@ module Coverband
95
96
  @redis_ttl = 2_592_000 # in seconds. Default is 30 days.
96
97
  @reporting_wiggle = nil
97
98
 
99
+ @trackers = []
100
+
98
101
  # TODO: these are deprecated
99
102
  @s3_region = nil
100
103
  @s3_bucket = nil
@@ -104,6 +107,31 @@ module Coverband
104
107
  @gem_details = false
105
108
  end
106
109
 
110
+ def railtie!
111
+ if Coverband.configuration.track_routes
112
+ Coverband.configuration.route_tracker = Coverband::Collectors::RouteTracker.new
113
+ trackers << Coverband.configuration.route_tracker
114
+ end
115
+
116
+ if Coverband.configuration.track_translations
117
+ Coverband.configuration.translations_tracker = Coverband::Collectors::TranslationTracker.new
118
+ trackers << Coverband.configuration.translations_tracker
119
+ end
120
+
121
+ if Coverband.configuration.track_views
122
+ Coverband.configuration.view_tracker = if Coverband.coverband_service?
123
+ Coverband::Collectors::ViewTrackerService.new
124
+ else
125
+ Coverband::Collectors::ViewTracker.new
126
+ end
127
+ trackers << Coverband.configuration.view_tracker
128
+ end
129
+ trackers.each { |tracker| tracker.railtie! }
130
+ rescue Redis::CannotConnectError => error
131
+ Coverband.configuration.logger.info "Redis is not available (#{error}), Coverband not configured"
132
+ Coverband.configuration.logger.info "If this is a setup task like assets:precompile feel free to ignore"
133
+ end
134
+
107
135
  def logger
108
136
  @logger ||= if defined?(Rails.logger) && Rails.logger
109
137
  Rails.logger
@@ -38,9 +38,7 @@ module Coverband
38
38
  # if deferred is set also sleep frst to spread load
39
39
  sleep(sleep_seconds.to_i) if Coverband.configuration.defer_eager_loading_data?
40
40
  Coverband.report_coverage
41
- Coverband.configuration.view_tracker&.report_views_tracked
42
- Coverband.configuration.route_tracker&.report_routes_tracked
43
- Coverband.configuration.translations_tracker&.save_report
41
+ Coverband.configuration.trackers.each { |tracker| tracker.save_report }
44
42
  if Coverband.configuration.verbose
45
43
  logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
46
44
  end
@@ -36,51 +36,49 @@ module Coverband
36
36
  return [401, {"www-authenticate" => 'Basic realm=""'}, [""]] unless check_auth
37
37
 
38
38
  request_path_info = request.path_info == "" ? "/" : request.path_info
39
- if request.post?
40
- case request_path_info
41
- when %r{\/clear_route_tracking_route}
42
- clear_route_tracking_route
43
- when %r{\/clear_route_tracking}
44
- clear_route_tracking
45
- when %r{\/clear_translation_tracking_key}
46
- clear_route_translation_key
47
- when %r{\/clear_translation_tracking}
48
- clear_translation_tracking
49
- when %r{\/clear_view_tracking_file}
50
- clear_view_tracking_file
51
- when %r{\/clear_view_tracking}
52
- clear_view_tracking
53
- when %r{\/clear_file}
54
- clear_file
55
- when %r{\/clear}
56
- clear
57
- else
58
- [404, {"Content-Type" => "text/html"}, ["404 error!"]]
39
+ tracker_route = false
40
+ Coverband.configuration.trackers.each do |tracker|
41
+ if request_path_info.match(tracker.class::REPORT_ROUTE)
42
+ tracker_route = true
43
+ if request_path_info =~ %r{\/clear_.*_key}
44
+ return clear_abstract_tracking_key(tracker)
45
+ elsif request_path_info =~ %r{\/clear_.*}
46
+ return clear_abstract_tracking(tracker)
47
+ else
48
+ return [200, {"Content-Type" => "text/html"}, [display_abstract_tracker(tracker)]]
49
+ end
59
50
  end
60
- else
61
- case request_path_info
62
- when /.*\.(css|js|gif|png)/
63
- @static.call(env)
64
- when %r{\/settings}
65
- [200, {"Content-Type" => "text/html"}, [settings]]
66
- when %r{\/view_tracker_data}
67
- [200, {"Content-Type" => "text/json"}, [view_tracker_data]]
68
- when %r{\/view_tracker}
69
- [200, {"Content-Type" => "text/html"}, [view_tracker]]
70
- when %r{\/route_tracker}
71
- [200, {"Content-Type" => "text/html"}, [route_tracker]]
72
- when %r{\/translations_tracker}
73
- [200, {"Content-Type" => "text/html"}, [translations_tracker]]
74
- when %r{\/enriched_debug_data}
75
- [200, {"Content-Type" => "text/json"}, [enriched_debug_data]]
76
- when %r{\/debug_data}
77
- [200, {"Content-Type" => "text/json"}, [debug_data]]
78
- when %r{\/load_file_details}
79
- [200, {"Content-Type" => "text/json"}, [load_file_details]]
80
- when %r{\/$}
81
- [200, {"Content-Type" => "text/html"}, [index]]
51
+ end
52
+
53
+ unless tracker_route
54
+ if request.post?
55
+ case request_path_info
56
+ when %r{\/clear_file}
57
+ clear_file
58
+ when %r{\/clear}
59
+ clear
60
+ else
61
+ [404, {"Content-Type" => "text/html"}, ["404 error!"]]
62
+ end
82
63
  else
83
- [404, {"Content-Type" => "text/html"}, ["404 error!"]]
64
+ case request_path_info
65
+ when /.*\.(css|js|gif|png)/
66
+ @static.call(env)
67
+ when %r{\/settings}
68
+ [200, {"Content-Type" => "text/html"}, [settings]]
69
+ when %r{\/view_tracker_data}
70
+ [200, {"Content-Type" => "text/json"}, [view_tracker_data]]
71
+ when %r{\/enriched_debug_data}
72
+ [200, {"Content-Type" => "text/json"}, [enriched_debug_data]]
73
+ when %r{\/debug_data}
74
+ [200, {"Content-Type" => "text/json"}, [debug_data]]
75
+ when %r{\/load_file_details}
76
+ [200, {"Content-Type" => "text/json"}, [load_file_details]]
77
+ when %r{\/$}
78
+ [200, {"Content-Type" => "text/html"}, [index]]
79
+ else
80
+ [404, {"Content-Type" => "text/html"}, ["404 error!"]]
81
+ end
84
82
  end
85
83
  end
86
84
  end
@@ -99,32 +97,17 @@ module Coverband
99
97
  Coverband::Utils::HTMLFormatter.new(nil, base_path: base_path).format_settings!
100
98
  end
101
99
 
102
- def view_tracker
103
- notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
104
- notice = request.params["notice"] ? notice : ""
105
- Coverband::Utils::HTMLFormatter.new(nil,
106
- notice: notice,
107
- base_path: base_path).format_view_tracker!
108
- end
109
-
110
- def route_tracker
111
- notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
112
- notice = request.params["notice"] ? notice : ""
113
- Coverband::Utils::HTMLFormatter.new(nil,
114
- notice: notice,
115
- base_path: base_path).format_route_tracker!
116
- end
117
-
118
- def translations_tracker
100
+ def display_abstract_tracker(tracker)
119
101
  notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
120
102
  notice = request.params["notice"] ? notice : ""
121
103
  Coverband::Utils::HTMLFormatter.new(nil,
104
+ tracker: tracker,
122
105
  notice: notice,
123
- base_path: base_path).format_translations_tracker!
106
+ base_path: base_path).format_abstract_tracker!
124
107
  end
125
108
 
126
109
  def view_tracker_data
127
- Coverband::Collectors::ViewTracker.new(store: Coverband.configuration.store).as_json
110
+ Coverband::Collectors::ViewTracker.new.as_json
128
111
  end
129
112
 
130
113
  def debug_data
@@ -168,73 +151,25 @@ module Coverband
168
151
  [302, {"Location" => "#{base_path}?notice=#{notice}"}, []]
169
152
  end
170
153
 
171
- def clear_view_tracking
172
- if Coverband.configuration.web_enable_clear
173
- tracker = Coverband::Collectors::ViewTracker.new(store: Coverband.configuration.store)
174
- tracker.reset_recordings
175
- notice = "view tracking reset"
176
- else
177
- notice = "web_enable_clear isn't enabled in your configuration"
178
- end
179
- [302, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
180
- end
181
-
182
- def clear_view_tracking_file
183
- if Coverband.configuration.web_enable_clear
184
- tracker = Coverband::Collectors::ViewTracker.new(store: Coverband.configuration.store)
185
- filename = request.params["filename"]
186
- tracker.clear_file!(filename)
187
- notice = "coverage for file #{filename} cleared"
188
- else
189
- notice = "web_enable_clear isn't enabled in your configuration"
190
- end
191
- [302, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
192
- end
193
-
194
- def clear_route_tracking
195
- if Coverband.configuration.web_enable_clear
196
- tracker = Coverband::Collectors::RouteTracker.new(store: Coverband.configuration.store)
197
- tracker.reset_recordings
198
- notice = "route tracking reset"
199
- else
200
- notice = "web_enable_clear isn't enabled in your configuration"
201
- end
202
- [302, {"Location" => "#{base_path}/route_tracker?notice=#{notice}"}, []]
203
- end
204
-
205
- def clear_route_tracking_route
206
- if Coverband.configuration.web_enable_clear
207
- tracker = Coverband::Collectors::RouteTracker.new(store: Coverband.configuration.store)
208
- route = request.params["route"]
209
- tracker.clear_route!(route)
210
- notice = "coverage for route #{route} cleared"
211
- else
212
- notice = "web_enable_clear isn't enabled in your configuration"
213
- end
214
- [302, {"Location" => "#{base_path}/route_tracker?notice=#{notice}"}, []]
215
- end
216
-
217
- def clear_translation_tracking
154
+ def clear_abstract_tracking(tracker)
218
155
  if Coverband.configuration.web_enable_clear
219
- tracker = Coverband::Collectors::TranslationTracker.new(store: Coverband.configuration.store)
220
156
  tracker.reset_recordings
221
- notice = "translation tracking reset"
157
+ notice = "#{tracker.title} tracking reset"
222
158
  else
223
159
  notice = "web_enable_clear isn't enabled in your configuration"
224
160
  end
225
- [302, {"Location" => "#{base_path}/translations_tracker?notice=#{notice}"}, []]
161
+ [302, {"Location" => "#{base_path}/#{tracker.route}?notice=#{notice}"}, []]
226
162
  end
227
163
 
228
- def clear_translation_tracking_key
164
+ def clear_abstract_tracking_key(tracker)
229
165
  if Coverband.configuration.web_enable_clear
230
- tracker = Coverband::Collectors::TranslationTracker.new(store: Coverband.configuration.store)
231
166
  key = request.params["key"]
232
167
  tracker.clear_key!(key)
233
- notice = "coverage for route #{key} cleared"
168
+ notice = "coverage for #{tracker.title} #{key} cleared"
234
169
  else
235
170
  notice = "web_enable_clear isn't enabled in your configuration"
236
171
  end
237
- [302, {"Location" => "#{base_path}/translations_tracker?notice=#{notice}"}, []]
172
+ [302, {"Location" => "#{base_path}/#{tracker.route}?notice=#{notice}"}, []]
238
173
  end
239
174
 
240
175
  private
@@ -13,11 +13,12 @@ require "time"
13
13
  module Coverband
14
14
  module Utils
15
15
  class HTMLFormatter
16
- attr_reader :notice, :base_path
16
+ attr_reader :notice, :base_path, :tracker
17
17
 
18
18
  def initialize(report, options = {})
19
19
  @notice = options.fetch(:notice, nil)
20
20
  @base_path = options.fetch(:base_path, "./")
21
+ @tracker = options.fetch(:tracker, nil)
21
22
  @coverage_result = Coverband::Utils::Results.new(report) if report
22
23
  end
23
24
 
@@ -33,16 +34,8 @@ module Coverband
33
34
  format_settings
34
35
  end
35
36
 
36
- def format_view_tracker!
37
- format_view_tracker
38
- end
39
-
40
- def format_route_tracker!
41
- format_route_tracker
42
- end
43
-
44
- def format_translations_tracker!
45
- format_translations_tracker
37
+ def format_abstract_tracker!
38
+ template("abstract_tracker").result(binding)
46
39
  end
47
40
 
48
41
  def format_source_file!(filename)
@@ -61,18 +54,6 @@ module Coverband
61
54
  template("settings").result(binding)
62
55
  end
63
56
 
64
- def format_view_tracker
65
- template("view_tracker").result(binding)
66
- end
67
-
68
- def format_route_tracker
69
- template("route_tracker").result(binding)
70
- end
71
-
72
- def format_translations_tracker
73
- template("translations_tracker").result(binding)
74
- end
75
-
76
57
  def format(result)
77
58
  Dir[File.join(File.dirname(__FILE__), "../../../public/*")].each do |path|
78
59
  FileUtils.cp_r(path, asset_output_path)
@@ -27,51 +27,7 @@ module Coverband
27
27
  Coverband.runtime_coverage!
28
28
  end
29
29
 
30
- begin
31
- if Coverband.configuration.track_routes
32
- if Gem::Version.new(Rails.version) >= Gem::Version.new("6.0.0") && Gem::Version.new(Rails.version) < Gem::Version.new("7.1.0")
33
- require_relative "rails6_ext"
34
- end
35
-
36
- Coverband.configuration.route_tracker = Coverband::Collectors::RouteTracker.new
37
-
38
- ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
39
- Coverband.configuration.route_tracker.track_routes(name, start, finish, id, payload)
40
- end
41
-
42
- # NOTE: This event was instrumented in Aug 10th 2022, but didn't make the 7.0.4 release and should be in the next release
43
- # https://github.com/rails/rails/pull/43755
44
- # Automatic tracking of redirects isn't avaible before Rails 7.1.0 (currently tested against the 7.1.0.alpha)
45
- # We could consider back porting or patching a solution that works on previous Rails versions
46
- ActiveSupport::Notifications.subscribe("redirect.action_dispatch") do |name, start, finish, id, payload|
47
- Coverband.configuration.route_tracker.track_routes(name, start, finish, id, payload)
48
- end
49
- end
50
-
51
- if Coverband.configuration.track_translations
52
- Coverband.configuration.translations_tracker = Coverband::Collectors::TranslationTracker.new
53
-
54
- # plugin to i18n
55
- I18n::Backend::Simple.send :include, Coverband::Collectors::I18n::KeyRegistry
56
- end
57
-
58
- if Coverband.configuration.track_views
59
- COVERBAND_VIEW_TRACKER = if Coverband.coverband_service?
60
- Coverband::Collectors::ViewTrackerService.new
61
- else
62
- Coverband::Collectors::ViewTracker.new
63
- end
64
-
65
- Coverband.configuration.view_tracker = COVERBAND_VIEW_TRACKER
66
-
67
- ActiveSupport::Notifications.subscribe(/render_(template|partial|collection).action_view/) do |name, start, finish, id, payload|
68
- COVERBAND_VIEW_TRACKER.track_views(name, start, finish, id, payload) unless name.include?("!")
69
- end
70
- end
71
- rescue Redis::CannotConnectError => error
72
- Coverband.configuration.logger.info "Redis is not available (#{error}), Coverband not configured"
73
- Coverband.configuration.logger.info "If this is a setup task like assets:precompile feel free to ignore"
74
- end
30
+ Coverband.configuration.railtie!
75
31
  end
76
32
 
77
33
  config.before_configuration do
@@ -5,5 +5,5 @@
5
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.2.6.rc.1"
8
+ VERSION = "5.2.6.rc.2"
9
9
  end
data/lib/coverband.rb CHANGED
@@ -16,6 +16,7 @@ require "coverband/adapters/stdout_store"
16
16
  require "coverband/adapters/null_store"
17
17
  require "coverband/utils/file_hasher"
18
18
  require "coverband/collectors/coverage"
19
+ require "coverband/collectors/abstract_tracker"
19
20
  require "coverband/collectors/view_tracker"
20
21
  require "coverband/collectors/view_tracker_service"
21
22
  require "coverband/collectors/route_tracker"