coverband 3.0.1 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/changes.md CHANGED
@@ -23,30 +23,20 @@ Will be the fully modern release that drops maintenance legacy support in favor
23
23
  - Support for file versions
24
24
  - md5 or release tags
25
25
  - add coverage timerange support
26
- - Drop Simplecov dependency
27
-
28
- ### Coverband 3.X
29
-
30
- Will be a stable and fast release that drops maintenance legacy support in favor of increased performance and maintainability.
31
-
32
- - expects to drop Tracepoint collection engine
33
- - drop anything below Ruby 2.3
34
- - release begins to simplify ease of use
35
- - drop collectors adapter
36
- - reduced configuration options
26
+ - Drop Simplecov dependency
37
27
  - improved web reporting
38
28
  - no longer relying directly on HTML in S3 but dynamically generated from any adapter
39
29
  - lists current config options
40
30
  - eventually allow updating remote config
41
31
  - full theming
42
- - list redis data dump for debugging
32
+ - list redis data dump for debugging
43
33
  - additional adapters: Memcache, S3, and ActiveRecord
44
- - add additional config / protection options on Coverage clear
45
- - add memory benchmarks showing memory overhead of coverband
46
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 additional config / protection options on Coverage clear
47
37
  - add meta data information first seen last recorded to the coverage report views (probably need to drop simplecov for that).
48
- - more details in this issue: https://github.com/danmayer/coverband/issues/118
49
- - use full stack tests to prove no memory leaks when used in Rails
38
+ - more details in this issue: https://github.com/danmayer/coverband/issues/118
39
+ - Make good video on setup, install, usage
50
40
 
51
41
  ### Coverband_jam_session
52
42
 
@@ -68,15 +58,36 @@ Feature Ideas:
68
58
  - tagging of reported Coverage
69
59
  - allow only to collect coverage based on route (limiting or scoped coverage)
70
60
  - coverage over some other variable like a set of alpha users
61
+ - document how to use this on staging / selenium test suite runs
62
+ - possible add API to pull report at end of run
71
63
 
72
64
  # Alpha
73
65
 
74
- ### Coverband ???
66
+ ### Coverband 4.0.0
75
67
 
76
68
  * Add support for Railties integration
69
+ * Reduce configuration options
70
+ * Default to background reporting vs middleware reporting
71
+ * Resolves issue requiring submitting initial coverage data pre-fork
72
+ * Simplified setup with just works sensible defaults for configuration out of the box
73
+ * Fixes on the pilot release of background reporting in 3.0.1
74
+ * Rake tasks automatically configured
75
+ * Updated and simplified documentation
77
76
 
78
77
  # Released
79
78
 
79
+ ### Coverband 3.X
80
+
81
+ Will be a stable and fast release that drops maintenance legacy support in favor of increased performance and maintainability.
82
+
83
+ - expects to drop Tracepoint collection engine
84
+ - drop anything below Ruby 2.3
85
+ - release begins to simplify ease of use
86
+ - drop collectors adapter
87
+ - reduced configuration options
88
+ - add memory benchmarks showing memory overhead of coverband
89
+ - use full stack tests to prove no memory leaks when used in Rails
90
+
80
91
  ### Coverband 3.0.1
81
92
 
82
93
  * update documentation around verification steps (https://github.com/danmayer/coverband/issues/135), thanks @kbaum
data/coverband.gemspec CHANGED
@@ -25,14 +25,13 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'aws-sdk', '~> 2'
26
26
  spec.add_development_dependency 'benchmark-ips'
27
27
  spec.add_development_dependency 'bundler', '~> 1.3'
28
+ spec.add_development_dependency 'm'
29
+ spec.add_development_dependency 'memory_profiler'
28
30
  spec.add_development_dependency 'mocha', '~> 0.14.0'
29
31
  spec.add_development_dependency 'rack'
30
32
  spec.add_development_dependency 'rack-test'
31
33
  spec.add_development_dependency 'rake'
32
- spec.add_development_dependency 'redis'
33
34
  spec.add_development_dependency 'test-unit'
34
- spec.add_development_dependency 'm'
35
- spec.add_development_dependency 'memory_profiler'
36
35
 
37
36
  # used for benchmarking and tests
38
37
  spec.add_development_dependency 'classifier-reborn'
@@ -40,6 +39,12 @@ Gem::Specification.new do |spec|
40
39
  # require 'byebug'; byebug
41
40
  spec.add_development_dependency 'pry-byebug'
42
41
 
42
+ # TODO: Remove when other production adapters exist
43
+ # because the default configuration of redis store, we really do require
44
+ # redis now. I was reluctant to add this, but until we offer another production
45
+ # quality adapter, I think this is more honest about requirements and reduces confusion
46
+ # without this there was a race condition on calling coverband configure before redis was loaded
47
+ spec.add_runtime_dependency 'redis'
43
48
  # TODO: make an optional dependency for simplecov reports
44
49
  # also likely should just require simplecov-html not the whole lib
45
50
  # I tried this but it was harder than I thought
data/lib/coverband.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'logger'
4
4
  require 'json'
5
+ require 'redis'
5
6
 
6
7
  require 'coverband/version'
7
8
  require 'coverband/configuration'
@@ -9,6 +10,7 @@ require 'coverband/adapters/base'
9
10
  require 'coverband/adapters/redis_store'
10
11
  require 'coverband/adapters/file_store'
11
12
  require 'coverband/utils/s3_report'
13
+ require 'coverband/utils/railtie' if defined? ::Rails::Railtie
12
14
  require 'coverband/collectors/coverage'
13
15
  require 'coverband/reporters/base'
14
16
  require 'coverband/reporters/simple_cov_report'
@@ -35,8 +37,7 @@ module Coverband
35
37
  elsif File.exist?(configuration_file)
36
38
  require configuration_file
37
39
  else
38
- msg = "configure requires a block, #{CONFIG_FILE} in project, or file path passed in configure"
39
- raise ArgumentError, msg
40
+ configuration.logger&.debug('using default configuration')
40
41
  end
41
42
  end
42
43
 
@@ -48,4 +49,11 @@ module Coverband
48
49
  Coverband::Collectors::Coverage.instance
49
50
  Background.start if configuration.background_reporting_enabled && !RackServerCheck.running?
50
51
  end
52
+
53
+ unless ENV['COVERBAND_DISABLE_AUTO_START']
54
+ # Coverband should be setup as early as possible
55
+ # to capture usage of things loaded by initializers or other Rails engines
56
+ configure
57
+ start
58
+ end
51
59
  end
@@ -17,7 +17,6 @@ module Coverband
17
17
  def reset_instance
18
18
  @project_directory = File.expand_path(Coverband.configuration.root)
19
19
  @file_line_usage = {}
20
- @ignored_files = Set.new
21
20
  @ignore_patterns = Coverband.configuration.ignore + ['internal:prelude', 'schema.rb']
22
21
  @reporting_frequency = Coverband.configuration.reporting_frequency
23
22
  @store = Coverband.configuration.store
@@ -25,19 +24,15 @@ module Coverband
25
24
  @logger = Coverband.configuration.logger
26
25
  @current_thread = Thread.current
27
26
  @test_env = Coverband.configuration.test_env
28
- @background_reporting_enabled = Coverband.configuration.background_reporting_enabled
27
+ @@previous_results = nil
29
28
  Thread.current[:coverband_instance] = nil
30
29
  self
31
30
  end
32
31
 
33
32
  def report_coverage(force_report = false)
34
- return Background.start if @background_reporting_enabled
35
33
  return if !ready_to_report? && !force_report
34
+ raise 'no Coverband store set' unless @store
36
35
 
37
- unless @store
38
- @logger.debug 'no store set, no-op'
39
- return
40
- end
41
36
  new_results = get_new_coverage_results
42
37
  add_filtered_files(new_results)
43
38
  @store.save_report(files_with_line_usage)
@@ -63,7 +58,6 @@ module Coverband
63
58
 
64
59
  def add_filtered_files(new_results)
65
60
  new_results.each_pair do |file, line_counts|
66
- next if @ignored_files.include?(file)
67
61
  next unless track_file?(file)
68
62
  add_file(file, line_counts)
69
63
  end
@@ -74,14 +68,12 @@ module Coverband
74
68
  end
75
69
 
76
70
  def get_new_coverage_results
77
- coverage_results = nil
78
- @semaphore.synchronize { coverage_results = new_coverage(::Coverage.peek_result.dup) }
79
- coverage_results
71
+ @semaphore.synchronize { new_coverage(::Coverage.peek_result.dup) }
80
72
  end
81
73
 
82
74
  def files_with_line_usage
83
75
  @file_line_usage.select do |_file_name, coverage|
84
- coverage.any? { |value| value && value.nonzero? }
76
+ coverage.any? { |value| value&.nonzero? }
85
77
  end
86
78
  end
87
79
 
@@ -2,10 +2,9 @@
2
2
 
3
3
  module Coverband
4
4
  class Configuration
5
- attr_accessor :redis, :root_paths, :root,
5
+ attr_accessor :root_paths, :root,
6
6
  :ignore, :additional_files, :verbose,
7
7
  :reporter, :reporting_frequency,
8
- :disable_on_failure_for,
9
8
  :redis_namespace, :redis_ttl,
10
9
  :safe_reload_files, :background_reporting_enabled,
11
10
  :background_reporting_sleep_seconds, :test_env
@@ -15,13 +14,16 @@ module Coverband
15
14
  def initialize
16
15
  @root = Dir.pwd
17
16
  @root_paths = []
18
- @ignore = []
17
+ @ignore = %w(vendor .erb$ .slim$)
19
18
  @additional_files = []
20
19
  @reporting_frequency = 0.0
21
20
  @verbose = false
22
21
  @reporter = 'scov'
23
- @logger = Logger.new(STDOUT)
22
+ @logger = nil
24
23
  @store = nil
24
+ @background_reporting_enabled = true
25
+ @background_reporting_sleep_seconds = 30
26
+ @test_env = nil
25
27
 
26
28
  # TODO: should we push these to adapter configs
27
29
  @s3_region = nil
@@ -30,12 +32,14 @@ module Coverband
30
32
  @s3_secret_access_key = nil
31
33
  @redis_namespace = nil
32
34
  @redis_ttl = nil
33
- @test_env = nil
34
- @background_reporting_sleep_seconds = 30
35
35
  end
36
36
 
37
37
  def logger
38
- @logger ||= Logger.new(STDOUT)
38
+ @logger ||= if defined?(Rails)
39
+ Rails.logger
40
+ else
41
+ Logger.new(STDOUT)
42
+ end
39
43
  end
40
44
 
41
45
  def s3_bucket
@@ -55,19 +59,26 @@ module Coverband
55
59
  end
56
60
 
57
61
  def store
58
- return @store if @store
59
- raise 'no valid store configured'
62
+ @store ||= Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_store_options)
60
63
  end
61
64
 
62
65
  def store=(store)
63
66
  if store.is_a?(Coverband::Adapters::Base)
64
67
  @store = store
65
- elsif defined?(Redis) && redis && redis.is_a?(Redis)
66
- @store = Coverband::Adapters::RedisStore.new(redis, ttl: Coverband.configuration.redis_ttl,
67
- redis_namespace: Coverband.configuration.redis_namespace)
68
- elsif store.is_a?(String)
69
- @store = Coverband::Adapters::FileStore.new(store)
68
+ else
69
+ raise 'please pass in an subclass of Coverband::Adapters for supported stores'
70
70
  end
71
71
  end
72
+
73
+ private
74
+
75
+ def redis_url
76
+ ENV['COVERBAND_REDIS_URL'] || ENV['REDIS_URL']
77
+ end
78
+
79
+ def redis_store_options
80
+ { ttl: Coverband.configuration.redis_ttl,
81
+ redis_namespace: Coverband.configuration.redis_namespace }
82
+ end
72
83
  end
73
84
  end
@@ -10,20 +10,21 @@ module Coverband
10
10
  logger = Coverband.configuration.logger
11
11
  @semaphore.synchronize do
12
12
  return if @background_reporting_running
13
+ logger&.debug('Starting background reporting')
13
14
 
14
15
  @background_reporting_running = true
15
16
  sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds
16
17
  Thread.new do
17
18
  loop do
18
- Coverband::Collectors::Coverage.instance.report_coverage
19
+ Coverband::Collectors::Coverage.instance.report_coverage(true)
19
20
  logger&.debug("Reported coverage from thread. Sleeping for #{sleep_seconds} seconds")
20
21
  sleep(sleep_seconds)
21
22
  end
22
23
  end
23
24
 
24
25
  at_exit do
25
- Coverband::Collectors::Coverage.instance.report_coverage
26
- logger&.debug("Reported coverage before exit")
26
+ Coverband::Collectors::Coverage.instance.report_coverage(true)
27
+ logger&.debug('Reported coverage before exit')
27
28
  end
28
29
  end
29
30
  end
@@ -9,7 +9,11 @@ module Coverband
9
9
  def call(env)
10
10
  @app.call(env)
11
11
  ensure
12
- Coverband::Collectors::Coverage.instance.report_coverage
12
+ if Coverband.configuration.background_reporting_enabled
13
+ Coverband::Background.start
14
+ else
15
+ Coverband::Collectors::Coverage.instance.report_coverage
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -93,7 +93,7 @@ module Coverband
93
93
  end
94
94
 
95
95
  def collect_coverage
96
- Coverband::Collectors::Coverage.instance.report_coverage
96
+ Coverband::Collectors::Coverage.instance.report_coverage(true)
97
97
  notice = 'coverband coverage collected'
98
98
  [301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
99
99
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ class Railtie < Rails::Railtie
5
+ initializer 'coverband.configure' do |app|
6
+ app.middleware.use Coverband::Middleware
7
+ end
8
+
9
+ config.after_initialize do
10
+ Coverband::Collectors::Coverage.instance.report_coverage(true)
11
+ end
12
+
13
+ rake_tasks do
14
+ load 'coverband/utils/tasks.rb'
15
+ end
16
+ end
17
+ end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :coverband do
4
+ Coverband.configure
5
+
4
6
  ###
5
- # note: If your project has set many simplecov filters.
7
+ # NOTE: If your project has set many simplecov filters.
6
8
  # You might want to override them and clear the filters.
7
9
  # Or run the task `coverage_no_filters` below.
8
10
  ###
9
- desc 'report runtime coverband code coverage'
11
+ desc 'report runtime Coverband code coverage'
10
12
  task coverage: :environment do
11
13
  if Coverband.configuration.reporter == 'scov'
12
14
  Coverband::Reporters::SimpleCovReport.report(Coverband.configuration.store)
@@ -30,11 +32,9 @@ namespace :coverband do
30
32
  end
31
33
 
32
34
  ###
33
- # You likely want to clear coverage after significant code changes.
34
- # You may want to have a hook that saves current coverband data on deploy
35
- # and then resets the coverband store data.
35
+ # clear data helpful for development or after configuration issues
36
36
  ###
37
- desc 'reset coverband coverage data'
37
+ desc 'reset Coverband coverage data, helpful for development, debugging, etc'
38
38
  task clear: :environment do
39
39
  Coverband.configuration.store.clear!
40
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coverband
4
- VERSION = '3.0.1'
4
+ VERSION = '4.0.0.alpha'
5
5
  end
@@ -78,7 +78,6 @@ namespace :benchmarks do
78
78
  # desc 'set up coverband with Redis'
79
79
  task :setup_redis do
80
80
  Coverband.configure do |config|
81
- config.redis = Redis.new
82
81
  config.root = Dir.pwd
83
82
  config.reporting_frequency = 100.0
84
83
  config.logger = $stdout
@@ -222,6 +221,12 @@ namespace :benchmarks do
222
221
  measure_memory
223
222
  end
224
223
 
224
+ desc 'runs memory leak check via Rails tests'
225
+ task memory_rails: [:setup] do
226
+ puts 'runs memory rails test to ensure we dont leak'
227
+ puts `COVERBAND_MEMORY_TEST=true bundle exec m test/unit/rails_full_stack_test.rb:22`
228
+ end
229
+
225
230
  desc 'runs benchmarks on reporting large sets of files to redis'
226
231
  task redis_reporting: [:setup] do
227
232
  puts 'runs benchmarks on reporting large sets of files to redis'
@@ -3,14 +3,22 @@
3
3
  require File.expand_path('../test_helper', File.dirname(__FILE__))
4
4
 
5
5
  class BackgroundTest < Test::Unit::TestCase
6
+ def setup
7
+ Coverband::Collectors::Coverage.instance.reset_instance
8
+ Coverband.configure do |config|
9
+ config.store = Coverband::Adapters::RedisStore.new(Redis.new)
10
+ config.background_reporting_enabled = true
11
+ end
12
+ Coverband::Background.instance_variable_set(:@background_reporting_running, nil)
13
+ end
14
+
6
15
  def test_start
7
16
  Thread.expects(:new).yields
8
17
  Coverband::Background.expects(:loop).yields
9
- Coverband::Collectors::Coverage.instance.expects(:report_coverage)
18
+
10
19
  Coverband::Background.expects(:sleep).with(30)
11
20
  Coverband::Background.expects(:at_exit).yields
12
- Coverband::Collectors::Coverage.instance.expects(:report_coverage)
21
+ Coverband::Collectors::Coverage.instance.expects(:report_coverage).twice
13
22
  2.times { Coverband::Background.start }
14
23
  end
15
24
  end
16
-
@@ -29,29 +29,19 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
29
29
  assert_equal Coverband::Adapters::RedisStore, coverband.instance_variable_get('@store').class
30
30
  end
31
31
 
32
- test 'reports coverage in background when background reporting enabled' do
33
- Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
34
- @coverband.reset_instance
35
- Coverband::Background.expects(:start)
36
- @coverband.report_coverage
37
- end
38
-
39
32
  test 'report_coverage raises errors in tests' do
40
- Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
41
33
  @coverband.reset_instance
42
- Coverband::Background.expects(:start).raises("Oh no")
34
+ @coverband.expects(:ready_to_report?).raises('Oh no')
43
35
  assert_raise RuntimeError do
44
36
  @coverband.report_coverage
45
37
  end
46
38
  end
47
39
 
48
40
  test 'report_coverage does not raise errors in non-test mode' do
49
- Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
50
41
  Coverband.configuration.stubs(:test_env).returns(false)
42
+ @coverband.expects(:ready_to_report?).raises('Oh no')
51
43
  @coverband.reset_instance
52
- Coverband::Background.expects(:start).raises("Oh no")
53
44
  @coverband.report_coverage
54
45
  end
55
-
56
46
  end
57
47
  end