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 +4 -4
- data/.standard.yml +1 -0
- data/changes.md +13 -2
- data/coverband.gemspec +3 -0
- data/lib/coverband.rb +13 -1
- data/lib/coverband/adapters/base.rb +0 -1
- data/lib/coverband/adapters/file_store.rb +38 -6
- data/lib/coverband/adapters/stdout_store.rb +41 -0
- data/lib/coverband/adapters/web_service_store.rb +155 -0
- data/lib/coverband/collectors/delta.rb +10 -0
- data/lib/coverband/collectors/view_tracker_service.rb +59 -0
- data/lib/coverband/configuration.rb +116 -43
- data/lib/coverband/integrations/background.rb +3 -3
- data/lib/coverband/reporters/base.rb +1 -2
- data/lib/coverband/reporters/web.rb +2 -4
- data/lib/coverband/utils/railtie.rb +9 -4
- data/lib/coverband/utils/tasks.rb +1 -0
- data/lib/coverband/version.rb +1 -1
- data/test/coverband/adapters/file_store_test.rb +6 -6
- data/test/coverband/adapters/web_service_store_test.rb +56 -0
- data/test/coverband/collectors/delta_test.rb +1 -0
- data/test/coverband/configuration_test.rb +52 -1
- data/test/coverband/integrations/background_test.rb +14 -3
- data/test/jruby_check.rb +1 -1
- data/test/test_helper.rb +4 -0
- metadata +50 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e236d323d6ce3fdb2d3bf5ea9a7514e2cc5758c50d422573cd0ffe0bf8a3f5b
|
4
|
+
data.tar.gz: 93c4a362420b64444efa41f74c4f21259e5891e23481885a3acd7472e2577c63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce5500c42de344046f55a277635f7f406e6e6675b7a77cbff0ba9986c86c5b066e3969ea8540043dc4aaa70c91b9648cda531660569209257d7ce04c7831180c
|
7
|
+
data.tar.gz: 9927e92ef9749a079ee56774d6e112cfa4ca2c21f9fd56cd60e0896bf588198fc5ff8e133baff74cc1bf1bb2d4ca2d9cbe8f99a655702879db464d90a71a5dbb
|
data/.standard.yml
CHANGED
@@ -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
|
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
|
|
data/coverband.gemspec
CHANGED
@@ -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
|
data/lib/coverband.rb
CHANGED
@@ -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
|
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
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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
|
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.
|
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
|
-
:
|
6
|
+
:verbose,
|
7
7
|
:reporter, :redis_namespace, :redis_ttl,
|
8
8
|
:background_reporting_enabled,
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
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 =
|
64
|
+
@background_reporting_sleep_seconds = nil
|
65
65
|
@test_env = nil
|
66
66
|
@web_enable_clear = false
|
67
|
-
@
|
68
|
-
@
|
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
|
-
@
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
115
|
-
|
127
|
+
def reporting_wiggle
|
128
|
+
@reporting_wiggle ||= 30
|
116
129
|
end
|
117
130
|
|
118
131
|
def store
|
119
|
-
@store ||=
|
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
|
-
|
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
|
@@ -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
|
-
|
19
|
-
|
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
|
-
|
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
|
|
data/lib/coverband/version.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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(
|
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(
|
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(
|
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
|
data/test/jruby_check.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -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.
|
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-
|
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.
|
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
|