coverband 5.0.0.rc.3 → 5.0.0.rc.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c59cff2fa063db7a0c165e9cfefa8607151ee39699bf57cbb6bb6fce849abe97
4
- data.tar.gz: 6fedd5cc2efd695370b3136f293209184b8c633e093ae75ac2f7d083c1eec13d
3
+ metadata.gz: 2e236d323d6ce3fdb2d3bf5ea9a7514e2cc5758c50d422573cd0ffe0bf8a3f5b
4
+ data.tar.gz: 93c4a362420b64444efa41f74c4f21259e5891e23481885a3acd7472e2577c63
5
5
  SHA512:
6
- metadata.gz: 75740ba292febb787cbb40beaa47b1a355d9303b23b43fc949d77f918848497fca538e080e86baf5d898b4a5001a9a838ed64846cb5a039a6aaa2a300f39edf0
7
- data.tar.gz: 6ed03c519ee7a4a5d24f6399c8a1a747d2de58d0a6370575f72bed528a18cd4d24c941c6e7f60902ced21883e4f664158a91881b3518577722323cb5cc5b904c
6
+ metadata.gz: ce5500c42de344046f55a277635f7f406e6e6675b7a77cbff0ba9986c86c5b066e3969ea8540043dc4aaa70c91b9648cda531660569209257d7ce04c7831180c
7
+ data.tar.gz: 9927e92ef9749a079ee56774d6e112cfa4ca2c21f9fd56cd60e0896bf588198fc5ff8e133baff74cc1bf1bb2d4ca2d9cbe8f99a655702879db464d90a71a5dbb
@@ -13,6 +13,7 @@ ignore: # default: []
13
13
  - Style/RedundantRegexpEscape # fix later, enforcement changed
14
14
  - Layout/ArrayAlignment # WTF all of master broken from a few changes in rubo
15
15
  - Performance/RegexpMatch # Rubocop / standardrb have this WRONG for Ruby 2.3/2.4 not compatiable
16
+ - Style/GlobalStdStream # Rubocop / standardrb have this WRONG for Ruby 2.3/2.4 not compatiable
16
17
  - "vendor/**/*"
17
18
  - "pkg/**/*"
18
19
  - "test/**/*":
data/changes.md CHANGED
@@ -7,7 +7,7 @@
7
7
  - [redis bitfield](https://stackoverflow.com/questions/47100606/optimal-way-to-store-array-of-integers-in-redis-database)
8
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
9
 
10
- ### Coverband 4.X
10
+ ### Coverband Future...
11
11
 
12
12
  Will be the fully modern release that drops maintenance legacy support in favor of increased performance, ease of use, and maintainability.
13
13
 
@@ -60,7 +60,18 @@ Will be the fully modern release that drops maintenance legacy support in favor
60
60
  - drops S3 support
61
61
  - drops static report support
62
62
  - drops gem support
63
- - ?
63
+ - only loaded web reporter files when required
64
+ - configuration improvements
65
+ - improved load order allowing more time for ENV vars (better dotenv, figaro, rails secrets support)
66
+ - all config options can be set via coverband config, not requiring ENV var support
67
+ - deprecation notices on soon to be removed config options
68
+ - config exceptions on invalid configuration combinations
69
+ - improved resque patching pattern
70
+ - improved default ignores
71
+ - additional adapters
72
+ - supports web-service adapter for http coverage collection
73
+ - support log/file adapter
74
+ - reduce logs / errors / alerts on bad startup configurations
64
75
 
65
76
  # Released
66
77
 
@@ -25,15 +25,18 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "memory_profiler"
26
26
  spec.add_development_dependency "minitest"
27
27
  spec.add_development_dependency "minitest-fork_executor"
28
+ spec.add_development_dependency "minitest-stub-const"
28
29
  spec.add_development_dependency "mocha", "~> 1.7.0"
29
30
  spec.add_development_dependency "rack"
30
31
  spec.add_development_dependency "rack-test"
31
32
  spec.add_development_dependency "rake"
32
33
  spec.add_development_dependency "resque"
34
+ spec.add_development_dependency "standard", "= 0.2.5"
33
35
  spec.add_development_dependency "standardrb"
34
36
 
35
37
  spec.add_development_dependency "coveralls"
36
38
  spec.add_development_dependency "minitest-profile"
39
+ spec.add_development_dependency "webmock"
37
40
 
38
41
  # TODO: Remove when other production adapters exist
39
42
  # because the default configuration of redis store, we really do require
@@ -12,9 +12,11 @@ require "coverband/adapters/base"
12
12
  require "coverband/adapters/redis_store"
13
13
  require "coverband/adapters/hash_redis_store"
14
14
  require "coverband/adapters/file_store"
15
+ require "coverband/adapters/stdout_store"
15
16
  require "coverband/utils/file_hasher"
16
17
  require "coverband/collectors/coverage"
17
18
  require "coverband/collectors/view_tracker"
19
+ require "coverband/collectors/view_tracker_service"
18
20
  require "coverband/reporters/base"
19
21
  require "coverband/reporters/console_report"
20
22
  require "coverband/integrations/background"
@@ -25,6 +27,7 @@ Coverband::Adapters::RedisStore = Coverband::Adapters::HashRedisStore if ENV["CO
25
27
 
26
28
  module Coverband
27
29
  @@configured = false
30
+ SERVICE_CONFIG = "./config/coverband_service.rb"
28
31
  CONFIG_FILE = "./config/coverband.rb"
29
32
  RUNTIME_TYPE = :runtime
30
33
  EAGER_TYPE = :eager_loading
@@ -33,7 +36,11 @@ module Coverband
33
36
  ALL_TYPES = TYPES + [:merged]
34
37
 
35
38
  def self.configure(file = nil)
36
- configuration_file = file || ENV.fetch("COVERBAND_CONFIG", CONFIG_FILE)
39
+ configuration_file = file || ENV["COVERBAND_CONFIG"]
40
+ if configuration_file.nil?
41
+ configuration_file = coverband_service? ? SERVICE_CONFIG : CONFIG_FILE
42
+ end
43
+
37
44
  configuration
38
45
  if block_given?
39
46
  yield(configuration)
@@ -46,6 +53,10 @@ module Coverband
46
53
  coverage_instance.reset_instance
47
54
  end
48
55
 
56
+ def self.coverband_service?
57
+ !!File.exist?(SERVICE_CONFIG)
58
+ end
59
+
49
60
  def self.configured?
50
61
  @@configured
51
62
  end
@@ -87,6 +98,7 @@ module Coverband
87
98
  private_class_method def self.coverage_instance
88
99
  Coverband::Collectors::Coverage.instance
89
100
  end
101
+
90
102
  unless ENV["COVERBAND_DISABLE_AUTO_START"]
91
103
  begin
92
104
  # Coverband should be setup as early as possible
@@ -112,7 +112,6 @@ module Coverband
112
112
  # transparently update from RUNTIME_TYPE = nil to RUNTIME_TYPE = :runtime
113
113
  # transparent update for format coveband_3_2
114
114
  old_report = coverage(nil, override_type: nil) if old_report.nil? && type == Coverband::RUNTIME_TYPE
115
-
116
115
  new_report = expand_report(new_report) unless options[:skip_expansion]
117
116
  keys = (new_report.keys + old_report.keys).uniq
118
117
  keys.each do |file|
@@ -3,14 +3,38 @@
3
3
  module Coverband
4
4
  module Adapters
5
5
  ###
6
- # FilesStore store a merged coverage file to local disk
7
- # Generally this is for testing and development
8
- # Not recommended for production deployment, as it doesn't handle concurrency
6
+ # FileStore store a merged coverage file to local disk
7
+ #
8
+ # Notes: Concurrency
9
+ # * threadsafe as the caller to save_report uses @semaphore.synchronize
10
+ # * file access process safe as each file written per process PID
11
+ #
12
+ # Usage:
13
+ # config.store = Coverband::Adapters::FileStore.new('log/coverage.log')
14
+ #
15
+ # View Reports:
16
+ # Using this assumes you are syncing the coverage files
17
+ # to some shared storage that is accessable outside of the production server
18
+ # download files to a system where you want to view the reports..
19
+ # When viewing coverage from the filestore adapter it merges all coverage
20
+ # files matching the path pattern, in this case `log/coverage.log.*`
21
+ #
22
+ # run: `bundle exec rake coverband:coverage_server`
23
+ # open http://localhost:1022/
24
+ #
25
+ # one could also build a report via code, the output is suitable to feed into SimpleCov
26
+ #
27
+ # ```
28
+ # coverband.configuration.store.merge_mode = true
29
+ # coverband.configuration.store.coverage
30
+ # ```
9
31
  ###
10
32
  class FileStore < Base
33
+ attr_accessor :merge_mode
11
34
  def initialize(path, _opts = {})
12
35
  super()
13
- @path = path
36
+ @path = "#{path}.#{::Process.pid}"
37
+ @merge_mode = false
14
38
 
15
39
  config_dir = File.dirname(@path)
16
40
  Dir.mkdir config_dir unless File.exist?(config_dir)
@@ -29,17 +53,25 @@ module Coverband
29
53
  end
30
54
 
31
55
  def coverage(_local_type = nil)
32
- if File.exist?(path)
56
+ if merge_mode
57
+ data = {}
58
+ Dir[path.sub(/\.\d+/, ".*")].each do |path|
59
+ data = merge_reports(data, JSON.parse(File.read(path)), skip_expansion: true)
60
+ end
61
+ data
62
+ elsif File.exist?(path)
33
63
  JSON.parse(File.read(path))
34
64
  else
35
65
  {}
36
66
  end
67
+ rescue Errno::ENOENT
68
+ {}
37
69
  end
38
70
 
39
71
  def save_report(report)
40
72
  data = report.dup
41
73
  data = merge_reports(data, coverage)
42
- File.open(path, "w") { |f| f.write(data.to_json) }
74
+ File.write(path, JSON.dump(data))
43
75
  end
44
76
 
45
77
  def raw_store
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ module Adapters
5
+ ###
6
+ # StdoutStore is for testing and development
7
+ #
8
+ # Usage:
9
+ # config.store = Coverband::Adapters::StdoutStore.new
10
+ ###
11
+ class StdoutStore < Base
12
+ def initialize(_opts = {})
13
+ super()
14
+ end
15
+
16
+ def clear!
17
+ # NOOP
18
+ end
19
+
20
+ def size
21
+ 0
22
+ end
23
+
24
+ def migrate!
25
+ raise NotImplementedError, "StdoutStore doesn't support migrations"
26
+ end
27
+
28
+ def coverage(_local_type = nil)
29
+ {}
30
+ end
31
+
32
+ def save_report(report)
33
+ $stdout.puts(report.to_json)
34
+ end
35
+
36
+ def raw_store
37
+ raise NotImplementedError, "StdoutStore doesn't support raw_store"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ module Adapters
5
+ ###
6
+ # WebServiceStore: store a checkpoint of coverage to a remote service
7
+ ###
8
+ class WebServiceStore < Base
9
+ attr_reader :coverband_url, :process_type, :runtime_env, :hostname, :pid
10
+
11
+ def initialize(coverband_url, opts = {})
12
+ super()
13
+ require "socket"
14
+ require "securerandom"
15
+ @coverband_url = coverband_url
16
+ @process_type = opts.fetch(:process_type) { $PROGRAM_NAME&.split("/")&.last || Coverband.configuration.process_type }
17
+ @hostname = opts.fetch(:hostname) { ENV["DYNO"] || Socket.gethostname.force_encoding("utf-8").encode }
18
+ @hostname = @hostname.delete("'", "").delete("’", "")
19
+ @runtime_env = opts.fetch(:runtime_env) { Coverband.configuration.coverband_env }
20
+ @failed_coverage_reports = []
21
+ end
22
+
23
+ def logger
24
+ Coverband.configuration.logger
25
+ end
26
+
27
+ def clear!
28
+ # done via service UI
29
+ raise "not supported via service"
30
+ end
31
+
32
+ def clear_file!(filename)
33
+ # done via service UI
34
+ raise "not supported via service"
35
+ end
36
+
37
+ # NOTE: Should support nil to mean not supported
38
+ # the size feature doesn't really makde sense for the service
39
+ def size
40
+ 0
41
+ end
42
+
43
+ ###
44
+ # Fetch coverband coverage via the API
45
+ # This would allow one to expore from the service and move back to the open source
46
+ # without having to reset coverage
47
+ ###
48
+ def coverage(local_type = nil, opts = {})
49
+ return if Coverband.configuration.service_disabled_dev_test_env?
50
+
51
+ local_type ||= opts.key?(:override_type) ? opts[:override_type] : type
52
+ env_filter = opts.key?(:env_filter) ? opts[:env_filter] : "production"
53
+ uri = URI("#{coverband_url}/api/coverage?type=#{local_type}&env_filter=#{env_filter}")
54
+ req = Net::HTTP::Get.new(uri, "Content-Type" => "application/json", "Coverband-Token" => Coverband.configuration.api_key)
55
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
56
+ http.request(req)
57
+ end
58
+ JSON.parse(res.body)
59
+ rescue => e
60
+ logger&.error "Coverband: Error while retrieving coverage #{e}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
61
+ end
62
+
63
+ def save_report(report)
64
+ return if report.empty?
65
+
66
+ # We set here vs initialize to avoid setting on the primary process vs child processes
67
+ @pid ||= ::Process.pid
68
+
69
+ # TODO: do we need dup
70
+ # TODO: we don't need upstream timestamps, server will track first_seen
71
+ Thread.new do
72
+ data = expand_report(report.dup)
73
+ full_package = {
74
+ collection_type: "coverage_delta",
75
+ collection_data: {
76
+ tags: {
77
+ process_type: process_type,
78
+ app_loading: type == Coverband::EAGER_TYPE,
79
+ runtime_env: runtime_env,
80
+ pid: pid,
81
+ hostname: hostname
82
+ },
83
+ file_coverage: data
84
+ }
85
+ }
86
+
87
+ save_coverage(full_package)
88
+ retry_failed_reports
89
+ end&.join
90
+ end
91
+
92
+ def raw_store
93
+ raise "not supported via service"
94
+ end
95
+
96
+ private
97
+
98
+ def retry_failed_reports
99
+ retries = []
100
+ @failed_coverage_reports.any? do
101
+ begin
102
+ report_body = @failed_coverage_reports.pop
103
+ send_report_body(report_body)
104
+ rescue
105
+ retries << report_body
106
+ end
107
+ end
108
+ retries.each do |report_body|
109
+ add_retry_message(report_body)
110
+ end
111
+ end
112
+
113
+ def add_retry_message(report_body)
114
+ if @failed_coverage_reports.length > 5
115
+ logger&.info "Coverband: The errored reporting queue has reached 5. Subsequent reports will not be transmitted"
116
+ else
117
+ @failed_coverage_reports << report_body
118
+ end
119
+ end
120
+
121
+ def save_coverage(data)
122
+ if Coverband.configuration.api_key.nil?
123
+ puts "Coverband: Error: no Coverband API key was found!"
124
+ return
125
+ end
126
+
127
+ coverage_body = {remote_uuid: SecureRandom.uuid, data: data}.to_json
128
+ send_report_body(coverage_body)
129
+ rescue => e
130
+ add_retry_message(coverage_body)
131
+ logger&.info "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
132
+ end
133
+
134
+ def send_report_body(coverage_body)
135
+ uri = URI("#{coverband_url}/api/collector")
136
+ req = ::Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Coverband-Token" => Coverband.configuration.api_key)
137
+ req.body = coverage_body
138
+ logger&.info "Coverband: saving (#{uri}) #{req.body}" if Coverband.configuration.verbose
139
+ res = ::Net::HTTP.start(
140
+ uri.hostname,
141
+ uri.port,
142
+ open_timeout: Coverband.configuration.coverband_timeout,
143
+ read_timeout: Coverband.configuration.coverband_timeout,
144
+ ssl_timeout: Coverband.configuration.coverband_timeout,
145
+ use_ssl: uri.scheme == "https"
146
+ ) do |http|
147
+ http.request(req)
148
+ end
149
+ if res.code.to_i >= 500
150
+ add_retry_message(coverage_body)
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -77,6 +77,16 @@ module Coverband
77
77
 
78
78
  def transform_oneshot_lines_results(results)
79
79
  results.each_with_object({}) do |(file, coverage), new_results|
80
+ ###
81
+ # Eager filter:
82
+ # Normally I would break this out into additional methods
83
+ # and improve the readability but this is in a tight loop
84
+ # on the critical performance path, and any refactoring I come up with
85
+ # would slow down the performance.
86
+ ###
87
+ next unless @@ignore_patterns.none? { |pattern| file.match(pattern) } &&
88
+ file.start_with?(@@project_directory)
89
+
80
90
  @@stubs[file] ||= ::Coverage.line_stub(file)
81
91
  transformed_line_counts = coverage[:oneshot_lines].each_with_object(@@stubs[file].dup) { |line_number, line_counts|
82
92
  line_counts[line_number - 1] = 1
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ module Collectors
5
+ ###
6
+ # This class extends view tracker to support web service reporting
7
+ ###
8
+ class ViewTrackerService < ViewTracker
9
+ def report_views_tracked
10
+ reported_time = Time.now.to_i
11
+ if views_to_record.any?
12
+ relative_views = views_to_record.map! do |view|
13
+ roots.each do |root|
14
+ view = view.gsub(/#{root}/, "")
15
+ end
16
+ view
17
+ end
18
+ save_tracked_views(views: relative_views, reported_time: reported_time)
19
+ end
20
+ self.views_to_record = []
21
+ rescue => e
22
+ # we don't want to raise errors if Coverband can't reach the service
23
+ logger&.error "Coverband: view_tracker failed to store, error #{e.class.name}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
24
+ end
25
+
26
+ def self.supported_version?
27
+ defined?(Rails) && defined?(Rails::VERSION) && Rails::VERSION::STRING.split(".").first.to_i >= 4
28
+ end
29
+
30
+ private
31
+
32
+ def logger
33
+ Coverband.configuration.logger
34
+ end
35
+
36
+ def save_tracked_views(views:, reported_time:)
37
+ uri = URI("#{Coverband.configuration.service_url}/api/collector")
38
+ req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Coverband-Token" => Coverband.configuration.api_key)
39
+ data = {
40
+ collection_type: "view_tracker_delta",
41
+ collection_data: {
42
+ tags: {
43
+ runtime_env: Coverband.configuration.coverband_env
44
+ },
45
+ collection_time: reported_time,
46
+ tracked_views: views
47
+ }
48
+ }
49
+ # puts "sending #{data}"
50
+ req.body = {remote_uuid: SecureRandom.uuid, data: data}.to_json
51
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
52
+ http.request(req)
53
+ end
54
+ rescue => e
55
+ logger&.error "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
56
+ end
57
+ end
58
+ end
59
+ end
@@ -3,23 +3,23 @@
3
3
  module Coverband
4
4
  class Configuration
5
5
  attr_accessor :root_paths, :root,
6
- :additional_files, :verbose,
6
+ :verbose,
7
7
  :reporter, :redis_namespace, :redis_ttl,
8
8
  :background_reporting_enabled,
9
- :background_reporting_sleep_seconds, :test_env,
10
- :web_enable_clear, :gem_details, :web_debug, :report_on_exit,
11
- :simulate_oneshot_lines_coverage, :track_views, :view_tracker,
12
- :reporting_wiggle
13
-
9
+ :test_env, :web_enable_clear, :gem_details, :web_debug, :report_on_exit,
10
+ :simulate_oneshot_lines_coverage,
11
+ :view_tracker
14
12
  attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id,
15
- :s3_secret_access_key, :password
13
+ :s3_secret_access_key, :password, :api_key, :service_url, :coverband_timeout, :service_dev_mode,
14
+ :service_test_mode, :process_type, :track_views, :redis_url,
15
+ :background_reporting_sleep_seconds, :reporting_wiggle
16
+
16
17
  attr_reader :track_gems, :ignore, :use_oneshot_lines_coverage
17
18
 
18
19
  #####
19
20
  # TODO: This is is brittle and not a great solution to avoid deploy time
20
21
  # actions polluting the 'runtime' metrics
21
22
  #
22
- # * should we skip /bin/rails webpacker:compile ?
23
23
  # * Perhaps detect heroku deployment ENV var opposed to tasks?
24
24
  #####
25
25
  IGNORE_TASKS = ["coverband:clear",
@@ -27,6 +27,7 @@ module Coverband
27
27
  "coverband:coverage_server",
28
28
  "coverband:migrate",
29
29
  "assets:precompile",
30
+ "webpacker:compile",
30
31
  "db:version",
31
32
  "db:create",
32
33
  "db:drop",
@@ -55,18 +56,16 @@ module Coverband
55
56
  @root_paths = []
56
57
  @ignore = IGNORE_DEFAULTS.dup
57
58
  @search_paths = TRACKED_DEFAULT_PATHS.dup
58
- @additional_files = []
59
59
  @verbose = false
60
60
  @reporter = "scov"
61
61
  @logger = nil
62
62
  @store = nil
63
63
  @background_reporting_enabled = true
64
- @background_reporting_sleep_seconds = 30
64
+ @background_reporting_sleep_seconds = nil
65
65
  @test_env = nil
66
66
  @web_enable_clear = false
67
- @track_gems = false
68
- @gem_details = false
69
- @track_views = false
67
+ @track_views = true
68
+ @view_tracker = nil
70
69
  @web_debug = false
71
70
  @report_on_exit = true
72
71
  @use_oneshot_lines_coverage = ENV["ONESHOT"] || false
@@ -76,15 +75,26 @@ module Coverband
76
75
  @all_root_patterns = nil
77
76
  @password = nil
78
77
 
78
+ # coverband service settings
79
+ @api_key = nil
80
+ @service_url = nil
81
+ @coverband_timeout = nil
82
+ @service_dev_mode = nil
83
+ @service_test_mode = nil
84
+ @proces_type = nil
85
+
86
+ @redis_url = nil
87
+ @redis_namespace = nil
88
+ @redis_ttl = 2_592_000 # in seconds. Default is 30 days.
89
+ @reporting_wiggle = nil
90
+
79
91
  # TODO: these are deprecated
80
92
  @s3_region = nil
81
93
  @s3_bucket = nil
82
94
  @s3_access_key_id = nil
83
95
  @s3_secret_access_key = nil
84
-
85
- @redis_namespace = nil
86
- @redis_ttl = 2_592_000 # in seconds. Default is 30 days.
87
- @reporting_wiggle = nil
96
+ @track_gems = false
97
+ @gem_details = false
88
98
  end
89
99
 
90
100
  def logger
@@ -99,37 +109,47 @@ module Coverband
99
109
  @password || ENV["COVERBAND_PASSWORD"]
100
110
  end
101
111
 
102
- def s3_bucket
103
- puts "deprecated, s3 is no longer support"
104
- end
105
-
106
- def s3_region
107
- puts "deprecated, s3 is no longer support"
108
- end
109
-
110
- def s3_access_key_id
111
- puts "deprecated, s3 is no longer support"
112
+ # The adjustments here either protect the redis or service from being overloaded
113
+ # the tradeoff being the delay in when reporting data is available
114
+ # if running your own redis increasing this number reduces load on the redis CPU
115
+ def background_reporting_sleep_seconds
116
+ @background_reporting_sleep_seconds ||= if service?
117
+ # default to 10m for service
118
+ Coverband.configuration.coverband_env == "production" ? 600 : 60
119
+ elsif store.is_a?(Coverband::Adapters::HashRedisStore)
120
+ # Default to 5 minutes if using the hash redis store
121
+ 300
122
+ else
123
+ 60
124
+ end
112
125
  end
113
126
 
114
- def s3_secret_access_key
115
- puts "deprecated, s3 is no longer support"
127
+ def reporting_wiggle
128
+ @reporting_wiggle ||= 30
116
129
  end
117
130
 
118
131
  def store
119
- @store ||= Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_store_options)
132
+ @store ||= if service?
133
+ raise "invalid configuration: unclear default store coverband expects either api_key or redis_url" if ENV["COVERBAND_REDIS_URL"]
134
+ require "coverband/adapters/web_service_store"
135
+ Coverband::Adapters::WebServiceStore.new(service_url)
136
+ else
137
+ Coverband::Adapters::RedisStore.new(Redis.new(url: redis_url), redis_store_options)
138
+ end
120
139
  end
121
140
 
122
141
  def store=(store)
123
142
  raise "Pass in an instance of Coverband::Adapters" unless store.is_a?(Coverband::Adapters::Base)
124
-
125
- # Default to 5 minutes if using the hash redis store
126
- # This is a safer default for the high server volumes that need the hash store
127
- # it should avoid overloading the redis with lots of load
128
- @background_reporting_sleep_seconds = 300 if store.is_a?(Coverband::Adapters::HashRedisStore)
143
+ raise "invalid configuration: only coverband service expects an API Key" if api_key && store.class.to_s != "Coverband::Adapters::WebServiceStore"
144
+ raise "invalid configuration: coverband service shouldn't have redis url set" if ENV["COVERBAND_REDIS_URL"] && store.class.to_s == "Coverband::Adapters::WebServiceStore"
129
145
 
130
146
  @store = store
131
147
  end
132
148
 
149
+ def track_views
150
+ @track_views ||= service_disabled_dev_test_env? ? false : true
151
+ end
152
+
133
153
  ###
134
154
  # Search Paths
135
155
  ###
@@ -151,10 +171,6 @@ module Coverband
151
171
  @ignore = (@ignore + ignored_array).uniq
152
172
  end
153
173
 
154
- def track_gems=(_value)
155
- puts "gem tracking is deprecated, setting this will be ignored"
156
- end
157
-
158
174
  def current_root
159
175
  @current_root ||= File.expand_path(Coverband.configuration.root).freeze
160
176
  end
@@ -171,7 +187,7 @@ module Coverband
171
187
  @all_root_patterns ||= all_root_paths.map { |path| /^#{path}/ }.freeze
172
188
  end
173
189
 
174
- SKIPPED_SETTINGS = %w[@s3_secret_access_key @store]
190
+ SKIPPED_SETTINGS = %w[@s3_secret_access_key @store @api_key @password]
175
191
  def to_h
176
192
  instance_variables
177
193
  .each_with_object({}) do |var, hash|
@@ -189,12 +205,69 @@ module Coverband
189
205
  Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.6.0")
190
206
  end
191
207
 
192
- private
193
-
194
208
  def redis_url
195
- ENV["COVERBAND_REDIS_URL"] || ENV["REDIS_URL"]
209
+ @redis_url ||= ENV["COVERBAND_REDIS_URL"] || ENV["REDIS_URL"]
196
210
  end
197
211
 
212
+ def api_key
213
+ @api_key ||= ENV["COVERBAND_API_KEY"]
214
+ end
215
+
216
+ def service_url
217
+ @service_url ||= ENV["COVERBAND_URL"] || "https://coverband.io"
218
+ end
219
+
220
+ def coverband_env
221
+ ENV["RACK_ENV"] || ENV["RAILS_ENV"] || (defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : "unknown")
222
+ end
223
+
224
+ def coverband_timeout
225
+ @coverband_timeout ||= coverband_env == "development" ? 5 : 2
226
+ end
227
+
228
+ def service_dev_mode
229
+ @service_dev_mode ||= ENV["COVERBAND_ENABLE_DEV_MODE"] || false
230
+ end
231
+
232
+ def service_test_mode
233
+ @service_dev_mode ||= ENV["COVERBAND_ENABLE_TEST_MODE"] || false
234
+ end
235
+
236
+ def process_type
237
+ @process_type ||= ENV["PROCESS_TYPE"] || "unknown"
238
+ end
239
+
240
+ def service?
241
+ Coverband.coverband_service? || !api_key.nil?
242
+ end
243
+
244
+ def service_disabled_dev_test_env?
245
+ (coverband_env == "test" && !Coverband.configuration.service_test_mode) ||
246
+ (coverband_env == "development" && !Coverband.configuration.service_dev_mode)
247
+ end
248
+
249
+ def s3_bucket
250
+ puts "deprecated, s3 is no longer support"
251
+ end
252
+
253
+ def s3_region
254
+ puts "deprecated, s3 is no longer support"
255
+ end
256
+
257
+ def s3_access_key_id
258
+ puts "deprecated, s3 is no longer support"
259
+ end
260
+
261
+ def s3_secret_access_key
262
+ puts "deprecated, s3 is no longer support"
263
+ end
264
+
265
+ def track_gems=(_value)
266
+ puts "gem tracking is deprecated, setting this will be ignored"
267
+ end
268
+
269
+ private
270
+
198
271
  def redis_store_options
199
272
  {ttl: Coverband.configuration.redis_ttl,
200
273
  redis_namespace: Coverband.configuration.redis_namespace}
@@ -28,18 +28,18 @@ module Coverband
28
28
  return if running?
29
29
 
30
30
  logger.debug("Coverband: Starting background reporting") if Coverband.configuration.verbose
31
- sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds
31
+ sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
32
32
  @thread = Thread.new {
33
33
  loop do
34
34
  Coverband.report_coverage
35
35
  Coverband.configuration.view_tracker&.report_views_tracked
36
36
  if Coverband.configuration.reporting_wiggle
37
- sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds + rand(Coverband.configuration.reporting_wiggle.to_i)
37
+ sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i + rand(Coverband.configuration.reporting_wiggle.to_i)
38
38
  end
39
39
  if Coverband.configuration.verbose
40
40
  logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
41
41
  end
42
- sleep(sleep_seconds)
42
+ sleep(sleep_seconds.to_i)
43
43
  end
44
44
  }
45
45
  end
@@ -101,8 +101,7 @@ module Coverband
101
101
  end
102
102
  end
103
103
 
104
- scov_style_report = fix_file_names(scov_style_report, roots)
105
- scov_style_report
104
+ fix_file_names(scov_style_report, roots)
106
105
  end
107
106
  end
108
107
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "coverband"
4
+
3
5
  begin
4
6
  require "rack"
5
7
  rescue LoadError
@@ -11,10 +13,6 @@ module Coverband
11
13
  class Web
12
14
  attr_reader :request
13
15
 
14
- def initialize
15
- init_web
16
- end
17
-
18
16
  def init_web
19
17
  full_path = Gem::Specification.find_by_name("coverband").full_gem_path
20
18
  @static = Rack::Static.new(self,
@@ -15,11 +15,16 @@ module Coverband
15
15
  app.middleware.use Coverband::BackgroundMiddleware
16
16
 
17
17
  if Coverband.configuration.track_views
18
- CoverbandViewTracker = Coverband::Collectors::ViewTracker.new
19
- Coverband.configuration.view_tracker = CoverbandViewTracker
18
+ COVERBAND_VIEW_TRACKER = if Coverband.coverband_service?
19
+ Coverband::Collectors::ViewTrackerService.new
20
+ else
21
+ Coverband::Collectors::ViewTracker.new
22
+ end
23
+
24
+ Coverband.configuration.view_tracker = COVERBAND_VIEW_TRACKER
20
25
 
21
26
  ActiveSupport::Notifications.subscribe(/render_partial.action_view|render_template.action_view/) do |name, start, finish, id, payload|
22
- CoverbandViewTracker.track_views(name, start, finish, id, payload) unless name.include?("!")
27
+ COVERBAND_VIEW_TRACKER.track_views(name, start, finish, id, payload) unless name.include?("!")
23
28
  end
24
29
  end
25
30
  rescue Redis::CannotConnectError => error
@@ -30,6 +35,7 @@ module Coverband
30
35
 
31
36
  config.after_initialize do
32
37
  unless Coverband.tasks_to_ignore?
38
+ Coverband.configure
33
39
  Coverband.eager_loading_coverage!
34
40
  Coverband.report_coverage
35
41
  Coverband.runtime_coverage!
@@ -39,7 +45,6 @@ module Coverband
39
45
  config.before_configuration do
40
46
  unless ENV["COVERBAND_DISABLE_AUTO_START"]
41
47
  begin
42
- Coverband.configure
43
48
  Coverband.start
44
49
  rescue Redis::CannotConnectError => error
45
50
  Coverband.configuration.logger.info "Redis is not available (#{error}), Coverband not configured"
@@ -12,6 +12,7 @@ namespace :coverband do
12
12
  desc "report runtime Coverband code coverage"
13
13
  task :coverage_server do
14
14
  Rake.application["environment"].invoke if Rake::Task.task_defined?("environment")
15
+ Coverband.configuration.store.merge_mode = true if Coverband.configuration.store.is_a?(Coverband::Adapters::FileStore)
15
16
  Rack::Server.start app: Coverband::Reporters::Web.new, Port: ENV.fetch("COVERBAND_COVERAGE_PORT", 1022).to_i
16
17
  end
17
18
 
@@ -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.0.0.rc.3"
8
+ VERSION = "5.0.0.rc.8"
9
9
  end
@@ -13,14 +13,13 @@ class AdaptersFileStoreTest < Minitest::Test
13
13
  def setup
14
14
  super
15
15
  @test_file_path = "/tmp/coverband_filestore_test_path.json"
16
- File.open(@test_file_path, "w") { |f| f.write(test_data.to_json) }
16
+ previous_file_path = "#{@test_file_path}.#{::Process.pid}"
17
+ `rm #{@test_file_path}` if File.exist?(@test_file_path)
18
+ `rm #{previous_file_path}` if File.exist?(previous_file_path)
19
+ File.open(previous_file_path, "w") { |f| f.write(test_data.to_json) }
17
20
  @store = Coverband::Adapters::FileStore.new(@test_file_path)
18
21
  end
19
22
 
20
- def test_size
21
- assert @store.size > 1
22
- end
23
-
24
23
  def test_coverage
25
24
  assert_equal @store.coverage["dog.rb"]["data"][0], 1
26
25
  assert_equal @store.coverage["dog.rb"]["data"][1], 2
@@ -31,7 +30,7 @@ class AdaptersFileStoreTest < Minitest::Test
31
30
  end
32
31
 
33
32
  def test_covered_files
34
- assert_equal @store.covered_files, ["dog.rb"]
33
+ assert @store.covered_files.include?("dog.rb")
35
34
  end
36
35
 
37
36
  def test_clear
@@ -43,6 +42,7 @@ class AdaptersFileStoreTest < Minitest::Test
43
42
  mock_file_hash
44
43
  @store.send(:save_report, "cat.rb" => [0, 1])
45
44
  assert_equal @store.coverage["cat.rb"]["data"][1], 1
45
+ assert @store.size > 1
46
46
  end
47
47
 
48
48
  def test_data
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("../../test_helper", File.dirname(__FILE__))
4
+ require File.expand_path("../../../lib/coverband/adapters/web_service_store", File.dirname(__FILE__))
5
+
6
+ class WebServiceStoreTest < Minitest::Test
7
+ COVERBAND_SERVICE_URL = "http://localhost:12345"
8
+ FAKE_API_KEY = "12345"
9
+
10
+ def setup
11
+ WebMock.disable_net_connect!
12
+ super
13
+ @store = Coverband::Adapters::WebServiceStore.new(COVERBAND_SERVICE_URL)
14
+ Coverband.configuration.store = @store
15
+ end
16
+
17
+ def test_coverage
18
+ Coverband.configuration.api_key = FAKE_API_KEY
19
+ stub_request(:post, "#{COVERBAND_SERVICE_URL}/api/collector").to_return(body: {status: "OK"}.to_json, status: 200)
20
+ mock_file_hash
21
+ @store.save_report(basic_coverage)
22
+ end
23
+
24
+ # TODO: sort out a retry test
25
+ # def test_retries
26
+ # Coverband.configuration.api_key = FAKE_API_KEY
27
+ # stub_request(:post, "#{COVERBAND_SERVICE_URL}/api/collector").to_return(body: {status: "OK"}.to_json, status: 200)
28
+ # mock_file_hash
29
+ # @store.save_report(basic_coverage)
30
+ # end
31
+
32
+ def test_no_webservice_call_without_api_key
33
+ Coverband.configuration.api_key = nil
34
+ mock_file_hash
35
+ @store.save_report(basic_coverage)
36
+ end
37
+
38
+ def test_clear
39
+ assert_raises RuntimeError do
40
+ @store.clear!
41
+ end
42
+ end
43
+
44
+ def test_clear_file
45
+ assert_raises RuntimeError do
46
+ @store.clear_file!("app_path/dog.rb")
47
+ end
48
+ end
49
+
50
+ def test_size
51
+ mock_file_hash
52
+ @store.type = :eager_loading
53
+ @store.save_report("app_path/dog.rb" => [0, 1, 1])
54
+ assert @store.size, 1
55
+ end
56
+ end
@@ -114,6 +114,7 @@ class CollectorsDeltaTest < Minitest::Test
114
114
  oneshot_lines: [2, 3]
115
115
  }
116
116
  }
117
+ Coverband::Collectors::Delta.class_variable_set(:@@project_directory, "dealership.rb")
117
118
  ::Coverage.expects(:line_stub).with("dealership.rb").returns([nil, 0, 0, nil])
118
119
  results = Coverband::Collectors::Delta.results(mock_coverage(current_coverage))
119
120
  expected = {
@@ -4,6 +4,7 @@ require File.expand_path("../test_helper", File.dirname(__FILE__))
4
4
 
5
5
  class BaseTest < Minitest::Test
6
6
  def setup
7
+ Coverband.configuration.reset
7
8
  super
8
9
  Coverband.configuration.reset
9
10
  Coverband.configure do |config|
@@ -52,7 +53,7 @@ class BaseTest < Minitest::Test
52
53
  assert_equal current_paths, Coverband.configuration.root_paths
53
54
  end
54
55
 
55
- test "store raises issues" do
56
+ test "store raises when not set to supported adapter" do
56
57
  Coverband::Collectors::Coverage.instance.reset_instance
57
58
  assert_raises RuntimeError do
58
59
  Coverband.configure do |config|
@@ -61,6 +62,56 @@ class BaseTest < Minitest::Test
61
62
  end
62
63
  end
63
64
 
65
+ test "store defaults to redis store" do
66
+ Coverband::Collectors::Coverage.instance.reset_instance
67
+ assert_equal Coverband.configuration.store.class, Coverband::Adapters::RedisStore
68
+ end
69
+
70
+ test "store is a service store when api_key is set" do
71
+ Coverband::Collectors::Coverage.instance.reset_instance
72
+ Coverband.configuration.reset
73
+ Coverband.configure do |config|
74
+ config.redis_url = nil
75
+ config.api_key = "test-key"
76
+ end
77
+ assert_equal Coverband.configuration.store.class.to_s, "Coverband::Adapters::WebServiceStore"
78
+ end
79
+
80
+ test "store raises when api key set but not set to service" do
81
+ Coverband::Collectors::Coverage.instance.reset_instance
82
+ Coverband.configuration.reset
83
+ assert_raises RuntimeError do
84
+ Coverband.configure do |config|
85
+ config.api_key = "test-key"
86
+ config.redis_url = "redis://localhost:3333"
87
+ config.store = Coverband::Adapters::RedisStore.new(Coverband::Test.redis, redis_namespace: "coverband_test")
88
+ end
89
+ end
90
+ end
91
+
92
+ test "store raises when api key and coverband redis env" do
93
+ Coverband::Collectors::Coverage.instance.reset_instance
94
+ Coverband.configuration.reset
95
+
96
+ env = ENV.to_hash.merge("COVERBAND_REDIS_URL" => "redis://localhost:3333")
97
+ Object.stub_const(:ENV, env) do
98
+ assert_raises RuntimeError do
99
+ Coverband.configure do |config|
100
+ config.api_key = "test-key"
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ test "store doesnt raises when api key and redis_url" do
107
+ Coverband::Collectors::Coverage.instance.reset_instance
108
+ Coverband.configuration.reset
109
+ Coverband.configure do |config|
110
+ config.api_key = "test-key"
111
+ config.redis_url = "redis://localhost:3333"
112
+ end
113
+ end
114
+
64
115
  test "use_oneshot_lines_coverage" do
65
116
  refute Coverband.configuration.use_oneshot_lines_coverage
66
117
 
@@ -12,18 +12,29 @@ class BackgroundTest < Minitest::Test
12
12
  end
13
13
  end
14
14
 
15
+ def setup
16
+ Coverband.configuration.reset
17
+ super
18
+ Coverband.configure do |config|
19
+ config.background_reporting_sleep_seconds = 60
20
+ Coverband.configuration.reporting_wiggle = 0
21
+ end
22
+ end
23
+
15
24
  def test_start
25
+ sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
16
26
  Thread.expects(:new).yields.returns(ThreadDouble.new(true))
17
27
  Coverband::Background.expects(:loop).yields
18
- Coverband::Background.expects(:sleep).with(30)
28
+ Coverband::Background.expects(:sleep).with(sleep_seconds)
19
29
  Coverband::Collectors::Coverage.instance.expects(:report_coverage).once
20
30
  2.times { Coverband::Background.start }
21
31
  end
22
32
 
23
33
  def test_start_with_wiggle
34
+ sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds.to_i
24
35
  Thread.expects(:new).yields.returns(ThreadDouble.new(true))
25
36
  Coverband::Background.expects(:loop).yields
26
- Coverband::Background.expects(:sleep).with(35)
37
+ Coverband::Background.expects(:sleep).with(sleep_seconds + 5)
27
38
  Coverband::Background.expects(:rand).with(10).returns(5)
28
39
  Coverband.configuration.reporting_wiggle = 10
29
40
  Coverband::Collectors::Coverage.instance.expects(:report_coverage).once
@@ -33,7 +44,7 @@ class BackgroundTest < Minitest::Test
33
44
  def test_start_dead_thread
34
45
  Thread.expects(:new).yields.returns(ThreadDouble.new(false)).twice
35
46
  Coverband::Background.expects(:loop).yields.twice
36
- Coverband::Background.expects(:sleep).with(30).twice
47
+ Coverband::Background.expects(:sleep).with(60).twice
37
48
  Coverband::Collectors::Coverage.instance.expects(:report_coverage).twice
38
49
  2.times { Coverband::Background.start }
39
50
  end
@@ -2,7 +2,7 @@ require "coverage"
2
2
 
3
3
  Coverage.start
4
4
 
5
- require "./test/dog.rb"
5
+ require "./test/dog"
6
6
 
7
7
  puts Coverage.peek_result
8
8
 
@@ -6,6 +6,7 @@ require "rubygems"
6
6
  require "simplecov"
7
7
  require "coveralls"
8
8
  require "minitest/autorun"
9
+ require "minitest/stub_const"
9
10
  require "mocha/minitest"
10
11
  require "ostruct"
11
12
  require "json"
@@ -21,6 +22,7 @@ require "coverband/utils/source_file"
21
22
  require "coverband/utils/lines_classifier"
22
23
  require "coverband/utils/results"
23
24
  require "coverband/reporters/html_report"
25
+ require "webmock/minitest"
24
26
 
25
27
  # require 'pry-byebug' unless ENV['CI'] # Ruby 2.3 on CI crashes on pry & JRuby doesn't support it
26
28
  require_relative "unique_files"
@@ -44,6 +46,7 @@ module Coverband
44
46
  end
45
47
 
46
48
  def self.reset
49
+ Coverband.configuration.reset
47
50
  Coverband.configuration.redis_namespace = "coverband_test"
48
51
  Coverband.configuration.store.instance_variable_set(:@redis_namespace, "coverband_test")
49
52
  Coverband.configuration.store.class.class_variable_set(:@@path_cache, {})
@@ -51,6 +54,7 @@ module Coverband
51
54
  Coverband::Collectors::Coverage.instance.reset_instance
52
55
  Coverband::Utils::RelativeFileConverter.reset
53
56
  Coverband::Utils::AbsoluteFileConverter.reset
57
+ Coverband.configuration.reporting_wiggle = 0
54
58
  Coverband.configuration.redis_namespace = "coverband_test"
55
59
  Coverband::Background.stop
56
60
  Coverband.configuration.store.instance_variable_set(:@redis, redis)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.rc.3
4
+ version: 5.0.0.rc.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-07-30 00:00:00.000000000 Z
12
+ date: 2020-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: benchmark-ips
@@ -95,6 +95,20 @@ dependencies:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: minitest-stub-const
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
98
112
  - !ruby/object:Gem::Dependency
99
113
  name: mocha
100
114
  requirement: !ruby/object:Gem::Requirement
@@ -165,6 +179,20 @@ dependencies:
165
179
  - - ">="
166
180
  - !ruby/object:Gem::Version
167
181
  version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: standard
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - '='
187
+ - !ruby/object:Gem::Version
188
+ version: 0.2.5
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - '='
194
+ - !ruby/object:Gem::Version
195
+ version: 0.2.5
168
196
  - !ruby/object:Gem::Dependency
169
197
  name: standardrb
170
198
  requirement: !ruby/object:Gem::Requirement
@@ -207,6 +235,20 @@ dependencies:
207
235
  - - ">="
208
236
  - !ruby/object:Gem::Version
209
237
  version: '0'
238
+ - !ruby/object:Gem::Dependency
239
+ name: webmock
240
+ requirement: !ruby/object:Gem::Requirement
241
+ requirements:
242
+ - - ">="
243
+ - !ruby/object:Gem::Version
244
+ version: '0'
245
+ type: :development
246
+ prerelease: false
247
+ version_requirements: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: '0'
210
252
  - !ruby/object:Gem::Dependency
211
253
  name: redis
212
254
  requirement: !ruby/object:Gem::Requirement
@@ -249,10 +291,13 @@ files:
249
291
  - lib/coverband/adapters/file_store.rb
250
292
  - lib/coverband/adapters/hash_redis_store.rb
251
293
  - lib/coverband/adapters/redis_store.rb
294
+ - lib/coverband/adapters/stdout_store.rb
295
+ - lib/coverband/adapters/web_service_store.rb
252
296
  - lib/coverband/at_exit.rb
253
297
  - lib/coverband/collectors/coverage.rb
254
298
  - lib/coverband/collectors/delta.rb
255
299
  - lib/coverband/collectors/view_tracker.rb
300
+ - lib/coverband/collectors/view_tracker_service.rb
256
301
  - lib/coverband/configuration.rb
257
302
  - lib/coverband/integrations/background.rb
258
303
  - lib/coverband/integrations/background_middleware.rb
@@ -319,6 +364,7 @@ files:
319
364
  - test/coverband/adapters/file_store_test.rb
320
365
  - test/coverband/adapters/hash_redis_store_test.rb
321
366
  - test/coverband/adapters/redis_store_test.rb
367
+ - test/coverband/adapters/web_service_store_test.rb
322
368
  - test/coverband/at_exit_test.rb
323
369
  - test/coverband/collectors/coverage_test.rb
324
370
  - test/coverband/collectors/delta_test.rb
@@ -420,7 +466,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
420
466
  - !ruby/object:Gem::Version
421
467
  version: 1.3.1
422
468
  requirements: []
423
- rubygems_version: 3.0.3
469
+ rubygems_version: 3.1.2
424
470
  signing_key:
425
471
  specification_version: 4
426
472
  summary: Rack middleware to measure production code usage (LOC runtime usage)
@@ -436,6 +482,7 @@ test_files:
436
482
  - test/coverband/adapters/file_store_test.rb
437
483
  - test/coverband/adapters/hash_redis_store_test.rb
438
484
  - test/coverband/adapters/redis_store_test.rb
485
+ - test/coverband/adapters/web_service_store_test.rb
439
486
  - test/coverband/at_exit_test.rb
440
487
  - test/coverband/collectors/coverage_test.rb
441
488
  - test/coverband/collectors/delta_test.rb