coverband 5.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 interal format
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.save_report(files_with_line_usage)
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, :logged_views, :views_to_record
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.reject { |view| recently_used_views.include?(view) }
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
- self.views_to_record = []
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
- return false if logged_views.include?(file)
141
-
142
- true
150
+ !@logged_views.include?(file)
143
151
  end
144
152
 
145
153
  def track_file?(file, options = {})
146
- @ignore_patterns.none? do |pattern|
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
- self.views_to_record = []
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
- @track_views ||= service_disabled_dev_test_env? ? false : true
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 avaiable by uncommenting this mode is never released
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 isnt enabled in your configuration"
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 isnt enabled in your configuration"
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 isnt enabled in your configuration"
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 isnt enabled in your configuration"
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(/render_partial.action_view|render_template.action_view/) do |name, start, finish, id, payload|
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"
@@ -55,7 +55,7 @@ module Coverband
55
55
  Dir[tracked_files].each do |file|
56
56
  absolute = File.expand_path(file)
57
57
  result[absolute] ||= {
58
- "data" => Array.new(File.foreach(absolute).count) { 0 },
58
+ "data" => [],
59
59
  "never_loaded" => true
60
60
  }
61
61
  end
@@ -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 compatability from 3-4
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)
@@ -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 '4.2.1.rc.1' ~> 4.2.1.rc to prerelease versions like v4.2.1.rc.2 and v4.2.1.rc.3
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.1.0'
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"
@@ -103,7 +103,7 @@ var hljs=new function(){function l(o){return o.replace(/&/gm,"&amp;").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 inteded as a selector (e.g. '#container')
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,"&amp;").replace(/<
397
397
  loadedHeight = $loaded.outerHeight(true);
398
398
  loadedWidth = $loaded.outerWidth(true);
399
399
 
400
- // Opens inital empty Colorbox prior to content being loaded.
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,"&amp;").replace(/<
983
983
  return;
984
984
  }
985
985
 
986
- // A small pause because some browsers will occassionaly report a
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 destory 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,
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/envionments"]
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/envionments"]
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/envionments",
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 invokation
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 doesnt raises when api key and redis_url" do
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 shold only be included for isolated processes
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