coverband 3.0.0 → 3.0.1.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: c2b0fe96cfa4c9cfd336166b498bdbbba7d297265b5a7883d423b1b19d4738ad
4
- data.tar.gz: 31b7d38ea823730d3855fa2203da308adc862c2c8320b756c10671873f6b016e
2
+ SHA1:
3
+ metadata.gz: b33132c4d855470c5510444a91b0df3a99ef3ee8
4
+ data.tar.gz: e9a6c32142c9421251ce7588dcb80a4686c48e45
5
5
  SHA512:
6
- metadata.gz: 1ec633dcb00294b67974c083853cdb28148ce93fc68783aaab87fe2c343a00b880c3f5b653573cca147ce3eb2e0a1aa2933ed3629d157284fc34873838971918
7
- data.tar.gz: 5f58cce89174ca835edcbc53ce9a30a53facc276ad7ae290510380c133e640abe899087132ceff408c959fa4be5f119e8d4bb2c31b3da2b2e66b72dfae62f931
6
+ metadata.gz: 74411fa1d49db9c7bea3b59e49fcc2432a48650ecfae86c2e09273623c48e148995606ce8bdde73aaa789e8973655394672c01967827e97cd345443cd3a39d2f
7
+ data.tar.gz: 37dbb381f412f2b11269dbf9550148ab97cd273d60e9afae47ee47772427c0855dd4fe286dce2e9c1e73f686f257a9154f72c928de3ca22cf50008a3c9594ceb
data/README.md CHANGED
@@ -194,8 +194,9 @@ run ActionController::Dispatcher.new
194
194
  # Verify Correct Installation
195
195
 
196
196
  * boot up your application
197
+ * run app and hit a controller (via a web request, at least one request must complete)
197
198
  * run `rake coverband:coverage` this will show app initialization coverage
198
- * run app and hit a controller (hit at least +1 time over your `config.startup_delay` setting default is 0)
199
+ * make another request, or enough that your reporting frequency will trigger
199
200
  * run `rake coverband:coverage` and you should see coverage increasing for the endpoints you hit.
200
201
 
201
202
  ## Installation Session
data/changes.md CHANGED
@@ -30,7 +30,7 @@ Will be the fully modern release that drops maintenance legacy support in favor
30
30
  Will be a stable and fast release that drops maintenance legacy support in favor of increased performance and maintainability.
31
31
 
32
32
  - expects to drop Tracepoint collection engine
33
- - expects to drop anything below Ruby 2.3
33
+ - drop anything below Ruby 2.3
34
34
  - release begins to simplify ease of use
35
35
  - drop collectors adapter
36
36
  - reduced configuration options
@@ -44,6 +44,8 @@ Will be a stable and fast release that drops maintenance legacy support in favor
44
44
  - add additional config / protection options on Coverage clear
45
45
  - add memory benchmarks showing memory overhead of coverband
46
46
  - add articles / podcasts like prontos readme https://github.com/prontolabs/pronto
47
+ - 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
47
49
 
48
50
  ### Coverband_jam_session
49
51
 
@@ -70,8 +72,12 @@ Feature Ideas:
70
72
 
71
73
  ### Coverband 3.0.1
72
74
 
73
- * ??? ;)
74
-
75
+ * update documentation around verification steps (https://github.com/danmayer/coverband/issues/135), thanks @kbaum
76
+ * resolve coverage drift issue, https://github.com/danmayer/coverband/issues/118, thanks for MD5 hash ideas @dnasseri and @kbaum
77
+ * first version of background thread coverage reporting https://github.com/danmayer/coverband/pull/138, thanks @kbaum
78
+ * auto-detection of Rack & Rails thanks @kbaum
79
+ * improved tests allowing exceptions to raise in tests @kbaum
80
+ * add support for both aws-sdk 1.x and 2.x thanks @jared
75
81
 
76
82
  # Released
77
83
 
@@ -19,22 +19,28 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ['lib']
21
21
 
22
+ # to test support for sdk 1, uncomment this line
23
+ # spec.add_development_dependency 'aws-sdk', '~> 1'
24
+ # to test sdk 2 use this one
22
25
  spec.add_development_dependency 'aws-sdk', '~> 2'
26
+ spec.add_development_dependency 'benchmark-ips'
23
27
  spec.add_development_dependency 'bundler', '~> 1.3'
24
28
  spec.add_development_dependency 'mocha', '~> 0.14.0'
25
29
  spec.add_development_dependency 'rack'
26
30
  spec.add_development_dependency 'rack-test'
27
31
  spec.add_development_dependency 'rake'
28
- spec.add_development_dependency 'test-unit'
29
32
  spec.add_development_dependency 'redis'
30
- spec.add_development_dependency 'benchmark-ips'
33
+ spec.add_development_dependency 'test-unit'
34
+ spec.add_development_dependency 'm'
35
+
31
36
  # used for benchmarking and tests
32
37
  spec.add_development_dependency 'classifier-reborn'
33
38
  # add when debugging
34
39
  # require 'byebug'; byebug
35
- spec.add_development_dependency 'byebug'
40
+ spec.add_development_dependency 'pry-byebug'
36
41
 
37
- # todo make an optional dependency for simplecov reports
42
+ # TODO: make an optional dependency for simplecov reports
38
43
  # also likely should just require simplecov-html not the whole lib
44
+ # I tried this but it was harder than I thought
39
45
  spec.add_runtime_dependency 'simplecov', '> 0.11.1'
40
46
  end
@@ -8,11 +8,13 @@ require 'coverband/configuration'
8
8
  require 'coverband/adapters/base'
9
9
  require 'coverband/adapters/redis_store'
10
10
  require 'coverband/adapters/file_store'
11
- require 'coverband/utils/s3_report_writer'
11
+ require 'coverband/utils/s3_report'
12
12
  require 'coverband/collectors/coverage'
13
13
  require 'coverband/reporters/base'
14
14
  require 'coverband/reporters/simple_cov_report'
15
15
  require 'coverband/reporters/console_report'
16
+ require 'coverband/integrations/background'
17
+ require 'coverband/integrations/rack_server_check'
16
18
  require 'coverband/reporters/web'
17
19
  require 'coverband/integrations/middleware'
18
20
  require 'coverband/integrations/background'
@@ -44,5 +46,6 @@ module Coverband
44
46
 
45
47
  def self.start
46
48
  Coverband::Collectors::Coverage.instance
49
+ Background.start if configuration.background_reporting_enabled && !RackServerCheck.running?
47
50
  end
48
51
  end
@@ -4,36 +4,70 @@ module Coverband
4
4
  module Adapters
5
5
  class Base
6
6
  def initialize
7
- raise 'abstract'
7
+ @file_hash_cache = {}
8
8
  end
9
9
 
10
10
  def clear!
11
11
  raise 'abstract'
12
12
  end
13
13
 
14
- def save_report(_report)
15
- raise 'abstract'
14
+ # Note: This could lead to slight race on redis
15
+ # where multiple processes pull the old coverage and add to it then push
16
+ # the Coverband 2 had the same issue,
17
+ # and the tradeoff has always been acceptable
18
+ def save_report(report)
19
+ data = report.dup
20
+ merge_reports(data, get_report)
21
+ save_coverage(data)
16
22
  end
17
23
 
18
24
  def coverage
19
- raise 'abstract'
25
+ simple_report(get_report)
20
26
  end
21
27
 
22
28
  def covered_files
29
+ coverage.keys || []
30
+ end
31
+
32
+ def covered_lines_for_file(file)
33
+ coverage[file] || []
34
+ end
35
+
36
+ protected
37
+
38
+ def save_coverage
23
39
  raise 'abstract'
24
40
  end
25
41
 
26
- def covered_lines_for_file(_file)
42
+ def get_report
27
43
  raise 'abstract'
28
44
  end
29
45
 
30
- protected
46
+ def file_hash(file)
47
+ @file_hash_cache[file] ||= Digest::MD5.file(file).hexdigest
48
+ end
49
+
50
+ def expand_report(report)
51
+ report_time = Time.now.to_i
52
+ report.each_pair do |key, line_data|
53
+ extended_data = {
54
+ 'first_updated_at' => report_time,
55
+ 'last_updated_at' => report_time,
56
+ 'file_hash' => file_hash(key),
57
+ 'data' => line_data
58
+ }
59
+ report[key] = extended_data
60
+ end
61
+ end
31
62
 
32
63
  def merge_reports(new_report, old_report)
64
+ new_report = expand_report(new_report)
33
65
  keys = (new_report.keys + old_report.keys).uniq
34
66
  keys.each do |file|
35
- new_report[file] = if new_report[file] && old_report[file]
36
- array_add(new_report[file], old_report[file])
67
+ new_report[file] = if new_report[file] &&
68
+ old_report[file] &&
69
+ new_report[file]['file_hash'] == old_report[file]['file_hash']
70
+ merge_expanded_data(new_report[file], old_report[file])
37
71
  elsif new_report[file]
38
72
  new_report[file]
39
73
  else
@@ -43,9 +77,24 @@ module Coverband
43
77
  new_report
44
78
  end
45
79
 
80
+ def merge_expanded_data(new_expanded, old_expanded)
81
+ {
82
+ 'first_updated_at' => old_expanded['first_updated_at'],
83
+ 'last_updated_at' => new_expanded['last_updated_at'],
84
+ 'file_hash' => new_expanded['file_hash'],
85
+ 'data' => array_add(new_expanded['data'], old_expanded['data'])
86
+ }
87
+ end
88
+
46
89
  def array_add(latest, original)
47
90
  latest.map.with_index { |v, i| (v && original[i]) ? v + original[i] : nil }
48
91
  end
92
+
93
+ def simple_report(report)
94
+ report.each_with_object({}) do |(key, extended_data), simple|
95
+ simple[key] = extended_data['data']
96
+ end
97
+ end
49
98
  end
50
99
  end
51
100
  end
@@ -8,9 +8,8 @@ module Coverband
8
8
  # Not recommended for production deployment
9
9
  ###
10
10
  class FileStore < Base
11
- attr_accessor :path
12
-
13
11
  def initialize(path, _opts = {})
12
+ super()
14
13
  @path = path
15
14
 
16
15
  config_dir = File.dirname(@path)
@@ -21,32 +20,15 @@ module Coverband
21
20
  File.delete(path) if File.exist?(path)
22
21
  end
23
22
 
24
- def save_report(report)
25
- merge_reports(report, coverage)
26
- save_coverage(report)
27
- end
28
-
29
- def coverage
30
- existing_data(path)
31
- end
32
-
33
- def covered_files
34
- report = existing_data(path)
35
- existing_data(path).merge(report).keys || []
36
- end
37
-
38
- def covered_lines_for_file(file)
39
- report = existing_data(path)
40
- report[file] || []
41
- end
42
-
43
23
  private
44
24
 
25
+ attr_accessor :path
26
+
45
27
  def save_coverage(report)
46
28
  File.open(path, 'w') { |f| f.write(report.to_json) }
47
29
  end
48
30
 
49
- def existing_data(path)
31
+ def get_report
50
32
  if File.exist?(path)
51
33
  JSON.parse(File.read(path))
52
34
  else
@@ -6,9 +6,10 @@ module Coverband
6
6
  # RedisStore store a merged coverage file to redis
7
7
  ###
8
8
  class RedisStore < Base
9
- BASE_KEY = 'coverband3'
9
+ BASE_KEY = 'coverband3_1'
10
10
 
11
11
  def initialize(redis, opts = {})
12
+ super()
12
13
  @redis = redis
13
14
  @ttl = opts[:ttl]
14
15
  @redis_namespace = opts[:redis_namespace]
@@ -18,27 +19,6 @@ module Coverband
18
19
  @redis.del(base_key)
19
20
  end
20
21
 
21
- def save_report(report)
22
- # Note: This could lead to slight races
23
- # where multiple processes pull the old coverage and add to it then push
24
- # the Coverband 2 had the same issue,
25
- # and the tradeoff has always been acceptable
26
- merge_reports(report, coverage)
27
- save_coverage(base_key, report)
28
- end
29
-
30
- def coverage
31
- get_report(base_key)
32
- end
33
-
34
- def covered_files
35
- coverage.keys
36
- end
37
-
38
- def covered_lines_for_file(file)
39
- coverage[file]
40
- end
41
-
42
22
  private
43
23
 
44
24
  attr_reader :redis
@@ -47,13 +27,13 @@ module Coverband
47
27
  @base_key ||= [BASE_KEY, @redis_namespace].compact.join('.')
48
28
  end
49
29
 
50
- def save_coverage(key, data)
51
- redis.set key, data.to_json
52
- redis.expire(key, @ttl) if @ttl
30
+ def save_coverage(data)
31
+ redis.set base_key, data.to_json
32
+ redis.expire(base_key, @ttl) if @ttl
53
33
  end
54
34
 
55
- def get_report(key)
56
- data = redis.get key
35
+ def get_report
36
+ data = redis.get base_key
57
37
  data ? JSON.parse(data) : {}
58
38
  end
59
39
  end
@@ -24,12 +24,16 @@ module Coverband
24
24
  @verbose = Coverband.configuration.verbose
25
25
  @logger = Coverband.configuration.logger
26
26
  @current_thread = Thread.current
27
+ @test_env = Coverband.configuration.test_env
28
+ @background_reporting_enabled = Coverband.configuration.background_reporting_enabled
27
29
  Thread.current[:coverband_instance] = nil
28
30
  self
29
31
  end
30
32
 
31
33
  def report_coverage(force_report = false)
34
+ return Background.start if @background_reporting_enabled
32
35
  return if !ready_to_report? && !force_report
36
+
33
37
  unless @store
34
38
  @logger.debug 'no store set, no-op'
35
39
  return
@@ -44,6 +48,7 @@ module Coverband
44
48
  @logger.error "error: #{err.inspect} #{err.message}"
45
49
  @logger.error err.backtrace
46
50
  end
51
+ raise err if @test_env
47
52
  end
48
53
 
49
54
  protected
@@ -7,7 +7,8 @@ module Coverband
7
7
  :reporter, :reporting_frequency,
8
8
  :disable_on_failure_for,
9
9
  :redis_namespace, :redis_ttl,
10
- :safe_reload_files
10
+ :safe_reload_files, :background_reporting_enabled,
11
+ :background_reporting_sleep_seconds, :test_env
11
12
 
12
13
  attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id, :s3_secret_access_key
13
14
 
@@ -29,6 +30,8 @@ module Coverband
29
30
  @s3_secret_access_key = nil
30
31
  @redis_namespace = nil
31
32
  @redis_ttl = nil
33
+ @test_env = nil
34
+ @background_reporting_sleep_seconds = 30
32
35
  end
33
36
 
34
37
  def logger
@@ -2,6 +2,30 @@
2
2
 
3
3
  module Coverband
4
4
  class Background
5
- # TODO: stub to implement background thread recording
5
+ @semaphore = Mutex.new
6
+
7
+ def self.start
8
+ return if @background_reporting_running
9
+
10
+ logger = Coverband.configuration.logger
11
+ @semaphore.synchronize do
12
+ return if @background_reporting_running
13
+
14
+ @background_reporting_running = true
15
+ sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds
16
+ Thread.new do
17
+ loop do
18
+ Coverband::Collectors::Coverage.instance.report_coverage
19
+ logger&.debug("Reported coverage from thread. Sleeping for #{sleep_seconds} seconds")
20
+ sleep(sleep_seconds)
21
+ end
22
+ end
23
+
24
+ at_exit do
25
+ Coverband::Collectors::Coverage.instance.report_coverage
26
+ logger&.debug("Reported coverage before exit")
27
+ end
28
+ end
29
+ end
6
30
  end
7
31
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ class RackServerCheck
5
+ def self.running?
6
+ new(Kernel.caller_locations).running?
7
+ end
8
+
9
+ def initialize(stack)
10
+ @stack = stack
11
+ end
12
+
13
+ def running?
14
+ rack_server? || rails_server?
15
+ end
16
+
17
+ def rack_server?
18
+ @stack.any? { |line| line.path.include?('lib/rack/') }
19
+ end
20
+
21
+ def rails_server?
22
+ @stack.any? do |location|
23
+ location.path.include?('rails/commands/commands_tasks.rb') && location.label == 'server'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -38,13 +38,7 @@ module Coverband
38
38
  Coverband.configuration.logger.info "report is ready and viewable: open #{SimpleCov.coverage_dir}/index.html"
39
39
  end
40
40
 
41
- s3_writer_options = {
42
- region: Coverband.configuration.s3_region,
43
- access_key_id: Coverband.configuration.s3_access_key_id,
44
- secret_access_key: Coverband.configuration.s3_secret_access_key
45
- }
46
- Coverband::Utils::S3ReportWriter.new(Coverband.configuration.s3_bucket,
47
- s3_writer_options).persist! if Coverband.configuration.s3_bucket
41
+ Coverband::Utils::S3Report.instance.persist! if Coverband.configuration.s3_bucket
48
42
  end
49
43
  end
50
44
  end
@@ -71,7 +71,7 @@ module Coverband
71
71
  end
72
72
 
73
73
  def show
74
- html = s3.get_object(bucket: Coverband.configuration.s3_bucket, key: 'coverband/index.html').body.read
74
+ html = Coverband::Utils::S3Report.instance.retrieve
75
75
  # HACK: the static HTML assets to link to the path where this was mounted
76
76
  html = html.gsub("src='", "src='#{base_path}")
77
77
  html = html.gsub("href='", "href='#{base_path}")
@@ -126,30 +126,12 @@ module Coverband
126
126
 
127
127
  # This method should get the root mounted endpoint
128
128
  # for example if the app is mounted like so:
129
- # mount Coverband::S3Web, at: '/coverage'
129
+ # mount Coverband::Web, at: '/coverage'
130
130
  # "/coverage/collect_coverage?" become:
131
131
  # /coverage/
132
132
  def base_path
133
133
  request.path.match("\/.*\/") ? request.path.match("\/.*\/")[0] : '/'
134
134
  end
135
-
136
- def s3
137
- begin
138
- require 'aws-sdk'
139
- rescue StandardError
140
- Coverband.configuration.logger.error "coverband requires 'aws-sdk' in order use S3ReportWriter."
141
- return
142
- end
143
- @s3 ||= begin
144
- client_options = {
145
- region: Coverband.configuration.s3_region,
146
- access_key_id: Coverband.configuration.s3_access_key_id,
147
- secret_access_key: Coverband.configuration.s3_secret_access_key
148
- }
149
- client_options = {} if client_options.values.any?(&:nil?)
150
- Aws::S3::Client.new(client_options)
151
- end
152
- end
153
135
  end
154
136
  end
155
137
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coverband
4
+ module Utils
5
+ ###
6
+ # TODO: this is currently a html report writer
7
+ # this should support writing coverage the current method should be fine
8
+ # to write every report to S3 and sum them later or use the 2 pass
9
+ # method we do for redis if in a background thread
10
+ ###
11
+ class S3Report
12
+ def self.instance
13
+ s3_options = {
14
+ region: Coverband.configuration.s3_region,
15
+ access_key_id: Coverband.configuration.s3_access_key_id,
16
+ secret_access_key: Coverband.configuration.s3_secret_access_key
17
+ }
18
+ new(Coverband.configuration.s3_bucket, s3_options)
19
+ end
20
+
21
+ def initialize(bucket_name, options = {})
22
+ @bucket_name = bucket_name
23
+ @region = options[:region]
24
+ @access_key_id = options[:access_key_id]
25
+ @secret_access_key = options[:secret_access_key]
26
+ begin
27
+ require 'aws-sdk'
28
+ rescue StandardError
29
+ err_msg = 'coverband requires aws-sdk in order use S3Report.'
30
+ Coverband.configuration.logger.error err_msg
31
+ return
32
+ end
33
+ end
34
+
35
+ def persist!
36
+ if defined?(Aws)
37
+ object.put(body: coverage_content)
38
+ else
39
+ object.write(coverage_content)
40
+ end
41
+ end
42
+
43
+ def retrieve
44
+ if defined?(Aws)
45
+ s3_client.get_object(bucket: Coverband.configuration.s3_bucket,
46
+ key: 'coverband/index.html').body.read
47
+ else
48
+ object.read
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def coverage_content
55
+ version = Gem::Specification.find_by_name('simplecov-html').version.version
56
+ File.read("#{SimpleCov.coverage_dir}/index.html").gsub("./assets/#{version}/", '')
57
+ rescue StandardError
58
+ File.read("#{SimpleCov.coverage_dir}/index.html").to_s.gsub('./assets/0.10.1/', '')
59
+ end
60
+
61
+ def object
62
+ if defined?(Aws)
63
+ bucket.object('coverband/index.html')
64
+ else
65
+ bucket.objects['coverband/index.html']
66
+ end
67
+ end
68
+
69
+ def client_options
70
+ {
71
+ region: @region,
72
+ access_key_id: @access_key_id,
73
+ secret_access_key: @secret_access_key
74
+ }
75
+ end
76
+
77
+ def s3_client
78
+ if defined?(Aws)
79
+ # AWS SDK v2
80
+ Aws::S3::Client.new(client_options)
81
+ else
82
+ # AWS SDK v1
83
+ AWS::S3::Client.new(client_options)
84
+ end
85
+ end
86
+
87
+ def s3
88
+ resource_options = { client: s3_client }
89
+ resource_options = {} if client_options.values.any?(&:nil?)
90
+ if defined?(Aws)
91
+ # AWS SDK v2
92
+ Aws::S3::Resource.new(resource_options)
93
+ else
94
+ # AWS SDK v1
95
+ AWS::S3.new(resource_options)
96
+ end
97
+ end
98
+
99
+ def bucket
100
+ if defined?(Aws)
101
+ s3.bucket(@bucket_name)
102
+ else
103
+ s3.buckets[@bucket_name]
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coverband
4
- VERSION = '3.0.0'
4
+ VERSION = '3.0.1.alpha'
5
5
  end
@@ -169,6 +169,18 @@ namespace :benchmarks do
169
169
  def reporting_speed
170
170
  report = fake_report
171
171
  store = benchmark_redis_store
172
+ store.clear!
173
+
174
+ ###
175
+ # this is a hack because in the benchmark we don't have real files
176
+ ###
177
+ def store.file_hash(file)
178
+ if @file_hash_cache[file]
179
+ @file_hash_cache[file]
180
+ else
181
+ @file_hash_cache[file] = Digest::MD5.file(__FILE__).hexdigest
182
+ end
183
+ end
172
184
 
173
185
  5.times { store.save_report(report) }
174
186
  Benchmark.ips do |x|
@@ -198,7 +210,7 @@ namespace :benchmarks do
198
210
  desc 'benchmarks external requests to coverband_demo site'
199
211
  task :coverband_demo do
200
212
  # for local testing
201
- # puts `ab -n 200 -c 5 "http://127.0.0.1:3000/posts"`
213
+ # puts `ab -n 500 -c 5 "http://127.0.0.1:3000/posts"`
202
214
  puts `ab -n 2000 -c 10 "https://coverband-demo.herokuapp.com/posts"`
203
215
  end
204
216
 
@@ -206,6 +218,7 @@ namespace :benchmarks do
206
218
  task :coverband_demo_graph do
207
219
  # for local testing
208
220
  # puts `ab -n 200 -c 5 "http://127.0.0.1:3000/posts"`
221
+ #puts `ab -n 500 -c 10 -g tmp/ab_brench.tsv "http://127.0.0.1:3000/posts"`
209
222
  puts `ab -n 2000 -c 10 -g tmp/ab_brench.tsv "https://coverband-demo.herokuapp.com/posts"`
210
223
  puts `test/benchmarks/graph_bench.sh`
211
224
  `open tmp/timeseries.jpg`
@@ -7,6 +7,7 @@ require 'mocha/setup'
7
7
  require 'ostruct'
8
8
  require 'json'
9
9
  require 'redis'
10
+ require 'pry-byebug'
10
11
 
11
12
  SimpleCov.start do
12
13
  add_filter 'specs/ruby/1.9.1/gems/'
@@ -14,10 +15,12 @@ SimpleCov.start do
14
15
  add_filter '/config/'
15
16
  end
16
17
 
17
- TEST_COVERAGE_FILE = '/tmp/fake_file.json'.freeze
18
+ TEST_COVERAGE_FILE = '/tmp/fake_file.json'
18
19
 
19
20
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
20
21
  $LOAD_PATH.unshift(File.dirname(__FILE__))
22
+
23
+ Mocha::Configuration.prevent(:stubbing_method_unnecessarily)
21
24
  Mocha::Configuration.prevent(:stubbing_non_existent_method)
22
25
 
23
26
  def test(name, &block)
@@ -37,6 +40,12 @@ def test(name, &block)
37
40
  end
38
41
  end
39
42
 
43
+ def mock_file_hash
44
+ mock_file = mock('mock_file')
45
+ mock_file.expects(:hexdigest).at_least_once.returns('abcd')
46
+ Digest::MD5.expects(:file).at_least_once.returns(mock_file)
47
+ end
48
+
40
49
  def example_line
41
50
  [0, 1, 2]
42
51
  end
@@ -68,3 +77,9 @@ Coverband.configure do |config|
68
77
  config.reporter = 'std_out'
69
78
  config.store = Coverband::Adapters::RedisStore.new(Redis.new)
70
79
  end
80
+
81
+ Coverband::Configuration.class_eval do
82
+ def test_env
83
+ true
84
+ end
85
+ end
@@ -6,23 +6,44 @@ class AdaptersBaseTest < Test::Unit::TestCase
6
6
  def setup
7
7
  @test_file_path = '/tmp/coverband_filestore_test_path.json'
8
8
  @store = Coverband::Adapters::FileStore.new(@test_file_path)
9
+ mock_file_hash
9
10
  end
10
11
 
11
12
  def test_covered_merge
12
- old_report = { '/Users/danmayer/projects/coverband_demo/config/coverband.rb' => [5, 7, nil],
13
- '/Users/danmayer/projects/coverband_demo/config/initializers/assets.rb' => [5, 5, nil],
14
- '/Users/danmayer/projects/coverband_demo/config/initializers/cookies_serializer.rb' => [5, 5, nil] }
15
- new_report = { '/Users/danmayer/projects/coverband_demo/config/coverband.rb' => [5, 7, nil],
16
- '/Users/danmayer/projects/coverband_demo/config/initializers/filter_logging.rb' => [5, 5, nil],
17
- '/Users/danmayer/projects/coverband_demo/config/initializers/wrap_parameters.rb' => [5, 5, nil],
18
- '/Users/danmayer/projects/coverband_demo/app/controllers/application_controller.rb' => [5, 5, nil] }
13
+ old_time = 1541958097
14
+ current_time = Time.now.to_i
15
+ old_data = {
16
+ 'first_updated_at' => old_time,
17
+ 'last_updated_at' => current_time,
18
+ 'file_hash' => 'abcd',
19
+ 'data' => [5, 7, nil]
20
+ }
21
+ old_report = { '/projects/coverband_demo/config/coverband.rb' => old_data,
22
+ '/projects/coverband_demo/config/initializers/assets.rb' => old_data,
23
+ '/projects/coverband_demo/config/initializers/cookies_serializer.rb' => old_data }
24
+ new_report = { '/projects/coverband_demo/config/coverband.rb' => [5, 7, nil],
25
+ '/projects/coverband_demo/config/initializers/filter_logging.rb' => [5, 7, nil],
26
+ '/projects/coverband_demo/config/initializers/wrap_parameters.rb' => [5, 7, nil],
27
+ '/projects/coverband_demo/app/controllers/application_controller.rb' => [5, 7, nil] }
28
+ expected_merge = {
29
+ 'first_updated_at' => old_time,
30
+ 'last_updated_at' => current_time,
31
+ 'file_hash' => 'abcd',
32
+ 'data' => [10, 14, nil]
33
+ }
34
+ new_data = {
35
+ 'first_updated_at' => current_time,
36
+ 'last_updated_at' => current_time,
37
+ 'file_hash' => 'abcd',
38
+ 'data' => [5, 7, nil]
39
+ }
19
40
  expected_result = {
20
- '/Users/danmayer/projects/coverband_demo/app/controllers/application_controller.rb' => [5, 5, nil],
21
- '/Users/danmayer/projects/coverband_demo/config/coverband.rb' => [10, 14, nil],
22
- '/Users/danmayer/projects/coverband_demo/config/initializers/assets.rb' => [5, 5, nil],
23
- '/Users/danmayer/projects/coverband_demo/config/initializers/cookies_serializer.rb' => [5, 5, nil],
24
- '/Users/danmayer/projects/coverband_demo/config/initializers/filter_logging.rb' => [5, 5, nil],
25
- '/Users/danmayer/projects/coverband_demo/config/initializers/wrap_parameters.rb' => [5, 5, nil]
41
+ '/projects/coverband_demo/app/controllers/application_controller.rb' => new_data,
42
+ '/projects/coverband_demo/config/coverband.rb' => expected_merge,
43
+ '/projects/coverband_demo/config/initializers/assets.rb' => old_data,
44
+ '/projects/coverband_demo/config/initializers/cookies_serializer.rb' => old_data,
45
+ '/projects/coverband_demo/config/initializers/filter_logging.rb' => new_data,
46
+ '/projects/coverband_demo/config/initializers/wrap_parameters.rb' => new_data
26
47
  }
27
48
  assert_equal expected_result, @store.send(:merge_reports, new_report, old_report)
28
49
  end
@@ -10,8 +10,8 @@ class AdaptersFileStoreTest < Test::Unit::TestCase
10
10
  end
11
11
 
12
12
  def test_covered_lines_for_file
13
- assert_equal @store.covered_lines_for_file('dog.rb')['1'], 1
14
- assert_equal @store.covered_lines_for_file('dog.rb')['2'], 2
13
+ assert_equal @store.covered_lines_for_file('dog.rb')[0], 1
14
+ assert_equal @store.covered_lines_for_file('dog.rb')[1], 2
15
15
  end
16
16
 
17
17
  def test_covered_lines_when_null
@@ -28,7 +28,8 @@ class AdaptersFileStoreTest < Test::Unit::TestCase
28
28
  end
29
29
 
30
30
  def test_save_report
31
- @store.send(:save_report, 'cat.rb' => [0,1])
31
+ mock_file_hash
32
+ @store.send(:save_report, 'cat.rb' => [0, 1])
32
33
  assert_equal @store.covered_lines_for_file('cat.rb')[1], 1
33
34
  end
34
35
 
@@ -36,7 +37,10 @@ class AdaptersFileStoreTest < Test::Unit::TestCase
36
37
 
37
38
  def test_data
38
39
  {
39
- 'dog.rb' => { 1 => 1, 2 => 2 }
40
+ 'dog.rb' => { 'data' => [1, 2, nil],
41
+ 'file_hash' => 'abcd',
42
+ 'first_updated_at' => 1541968729,
43
+ 'last_updated_at' => 1541968729 }
40
44
  }
41
45
  end
42
46
  end
@@ -12,27 +12,30 @@ class RedisTest < Test::Unit::TestCase
12
12
  end
13
13
 
14
14
  def test_coverage
15
+ mock_file_hash
15
16
  expected = basic_coverage
16
17
  @store.save_report(expected)
17
18
  assert_equal expected, @store.coverage
18
19
  end
19
20
 
20
21
  def test_coverage_increments
21
- expected = basic_coverage
22
- @store.save_report(expected)
22
+ mock_file_hash
23
+ expected = basic_coverage.dup
24
+ @store.save_report(basic_coverage.dup)
23
25
  assert_equal expected, @store.coverage
24
- @store.save_report(expected)
26
+ @store.save_report(basic_coverage.dup)
25
27
  assert_equal [0, 2, 4], @store.coverage['app_path/dog.rb']
26
28
  end
27
29
 
28
30
  def test_covered_lines_for_file
31
+ mock_file_hash
29
32
  expected = basic_coverage
30
33
  @store.save_report(expected)
31
34
  assert_equal example_line, @store.covered_lines_for_file('app_path/dog.rb')
32
35
  end
33
36
 
34
37
  def test_covered_lines_when_null
35
- assert_equal nil, @store.covered_lines_for_file('app_path/dog.rb')
38
+ assert_equal [], @store.covered_lines_for_file('app_path/dog.rb')
36
39
  end
37
40
 
38
41
  def test_clear
@@ -42,15 +45,6 @@ class RedisTest < Test::Unit::TestCase
42
45
 
43
46
  private
44
47
 
45
- def combined_report
46
- {
47
- "#{BASE_KEY}.dog.rb" => {
48
- new: example_hash,
49
- existing: {}
50
- }
51
- }
52
- end
53
-
54
48
  def test_data
55
49
  {
56
50
  '/Users/danmayer/projects/cover_band_server/app.rb' => { 54 => 1, 55 => 2 },
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
4
+
5
+ class BackgroundTest < Test::Unit::TestCase
6
+ def test_start
7
+ Thread.expects(:new).yields
8
+ Coverband::Background.expects(:loop).yields
9
+ Coverband::Collectors::Coverage.instance.expects(:report_coverage)
10
+ Coverband::Background.expects(:sleep).with(30)
11
+ Coverband::Background.expects(:at_exit).yields
12
+ Coverband::Collectors::Coverage.instance.expects(:report_coverage)
13
+ 2.times { Coverband::Background.start }
14
+ end
15
+ end
16
+
@@ -29,5 +29,29 @@ 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
+ test 'report_coverage raises errors in tests' do
40
+ Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
41
+ @coverband.reset_instance
42
+ Coverband::Background.expects(:start).raises("Oh no")
43
+ assert_raise RuntimeError do
44
+ @coverband.report_coverage
45
+ end
46
+ end
47
+
48
+ test 'report_coverage does not raise errors in non-test mode' do
49
+ Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
50
+ Coverband.configuration.stubs(:test_env).returns(false)
51
+ @coverband.reset_instance
52
+ Coverband::Background.expects(:start).raises("Oh no")
53
+ @coverband.report_coverage
54
+ end
55
+
32
56
  end
33
57
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
4
+
5
+ class CoverbandTest < Test::Unit::TestCase
6
+
7
+ test 'Coverband#start kicks off background reporting if enabled and not in rack server' do
8
+ Coverband.configuration.stubs(:background_reporting_enabled).returns(:true)
9
+ Coverband::RackServerCheck.expects(:running?).returns(false)
10
+ Coverband::Background.expects(:start)
11
+ Coverband.start
12
+ end
13
+
14
+ test 'Coverband#start delays background reporting if enabled and running in a rack server' do
15
+ Coverband.configuration.stubs(:background_reporting_enabled).returns(true)
16
+ Coverband::RackServerCheck.expects(:running?).returns(true)
17
+ Coverband::Background.expects(:start).never
18
+ Coverband.start
19
+ end
20
+
21
+ test 'Coverband#start does not kick off background reporting if not enabled' do
22
+ Coverband.configuration.stubs(:background_reporting_enabled).returns(false)
23
+ Coverband::Background.expects(:start).never
24
+ ::Coverband.start
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
4
+
5
+ class RackServerCheckTest < Test::Unit::TestCase
6
+
7
+ test 'returns true when running in rack server' do
8
+ caller_locations = ['blah/lib/rack/server.rb'].map{ |path| OpenStruct.new(path: path, label: 'foo') }
9
+ Kernel.expects(:caller_locations).returns(caller_locations)
10
+ assert_true(Coverband::RackServerCheck.running?)
11
+ end
12
+
13
+ test 'returns false when not running in rack server' do
14
+ caller_locations = ['blah/lib/sidekiq/worker.rb'].map{ |path| OpenStruct.new(path: path, label: 'foo') }
15
+ Kernel.expects(:caller_locations).returns(caller_locations)
16
+ assert_false(Coverband::RackServerCheck.running?)
17
+ end
18
+
19
+ test 'returns true if running within a rails server' do
20
+ caller_locations = [OpenStruct.new(path: '/lib/rails/commands/commands_tasks.rb', label: 'server')]
21
+ Kernel.expects(:caller_locations).returns(caller_locations)
22
+ assert_true(Coverband::RackServerCheck.running?)
23
+ end
24
+ end
@@ -103,8 +103,6 @@ class ReportsBaseTest < Test::Unit::TestCase
103
103
  lines_hit = [1, 3, 6]
104
104
  store.stubs(:coverage).returns(key => lines_hit)
105
105
  expected = { key => [1, 3, 6] }
106
- File.stubs(:exist?).returns(true)
107
- File.stubs(:foreach).returns(['line 1', 'line2', 'line3', 'line4', 'line5', 'line6'])
108
106
 
109
107
  assert_equal expected, Coverband::Reporters::Base.send(:get_current_scov_data_imp, store, roots)
110
108
  end
@@ -18,6 +18,7 @@ class SimpleCovReportTest < Test::Unit::TestCase
18
18
  config.reporting_frequency = 100.0
19
19
  end
20
20
  Coverband.configuration.logger.stubs('info')
21
+ mock_file_hash
21
22
  Coverband::Reporters::ConsoleReport
22
23
  .expects(:current_root)
23
24
  .returns('app_path')
@@ -11,15 +11,6 @@ class ReportsSimpleCovTest < Test::Unit::TestCase
11
11
  @store.clear!
12
12
  end
13
13
 
14
- def combined_report
15
- {
16
- "#{BASE_KEY}.test/unit/dog.rb" => {
17
- new: example_hash,
18
- existing: {}
19
- }
20
- }
21
- end
22
-
23
14
  test 'generate scov report' do
24
15
  Coverband.configure do |config|
25
16
  config.reporter = 'scov'
@@ -28,13 +19,13 @@ class ReportsSimpleCovTest < Test::Unit::TestCase
28
19
  config.ignore = ['notsomething.rb']
29
20
  end
30
21
  Coverband.configuration.logger.stubs('info')
22
+ mock_file_hash
31
23
  @store.send(:save_report, basic_coverage)
32
24
 
33
25
  SimpleCov.expects(:track_files)
34
26
  SimpleCov.expects(:add_not_loaded_files).returns({})
35
27
  SimpleCov::Result.any_instance.expects(:format!)
36
28
  SimpleCov.stubs(:root)
37
-
38
29
  Coverband::Reporters::SimpleCovReport.report(@store, open_report: false)
39
30
  end
40
31
  end
@@ -29,9 +29,7 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.2.0')
29
29
 
30
30
  test 'renders show content' do
31
31
  Coverband.configuration.s3_bucket = 'coverage-bucket'
32
- s3 = mock('s3')
33
- Aws::S3::Client.expects(:new).returns(s3)
34
- s3.expects(:get_object).with(bucket: 'coverage-bucket', key: 'coverband/index.html').returns mock('response', body: mock('body', read: 'content'))
32
+ Coverband::Utils::S3Report.any_instance.expects(:retrieve).returns('content')
35
33
  get '/show'
36
34
  assert last_response.ok?
37
35
  assert_equal 'content', last_response.body
@@ -0,0 +1,44 @@
1
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
2
+ require 'aws-sdk'
3
+
4
+ module Coverband
5
+ class S3ReportTest < Test::Unit::TestCase
6
+ def html_version
7
+ Gem::Specification.find_by_name('simplecov-html').version.version.to_s
8
+ rescue StandardError
9
+ '0.10.1'
10
+ end
11
+
12
+ test 'it writes the coverage report to s3' do
13
+ if defined?(Aws::S3::Resource)
14
+ # AWS v2
15
+ s3 = mock('s3_resource')
16
+ bucket = mock('bucket')
17
+ object = mock('object')
18
+ s3.expects(:bucket).with('coverage-bucket').returns(bucket)
19
+ bucket.expects(:object).with('coverband/index.html').returns(object)
20
+ File.expects(:read).at_least(0).returns("content ./assets/#{html_version}/")
21
+ object.expects(:put).with(body: 'content ')
22
+ Aws::S3::Resource.expects(:new).returns(s3)
23
+ else
24
+ # AWS v1
25
+ object = mock('object')
26
+ object.expects(:write).with('content ')
27
+ bucket = mock('bucket')
28
+ bucket.expects(:objects).returns('coverband/index.html' => object)
29
+ local_s3 = mock('s3_resource')
30
+ local_s3.expects(:buckets).returns('coverage-bucket' => bucket)
31
+ File.expects(:read).at_least(0).returns("content ./assets/#{html_version}/")
32
+ AWS::S3::Client.expects(:new).returns(nil)
33
+ AWS::S3.expects(:new).returns(local_s3)
34
+ end
35
+
36
+ s3_options = {
37
+ region: 'us-west-1',
38
+ access_key_id: '',
39
+ secret_access_key: ''
40
+ }
41
+ Coverband::Utils::S3Report.new('coverage-bucket', s3_options).persist!
42
+ end
43
+ end
44
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-04 00:00:00.000000000 Z
11
+ date: 2018-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: benchmark-ips
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +109,7 @@ dependencies:
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: test-unit
112
+ name: redis
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - ">="
@@ -109,7 +123,7 @@ dependencies:
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
- name: redis
126
+ name: test-unit
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
@@ -123,7 +137,7 @@ dependencies:
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
- name: benchmark-ips
140
+ name: m
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - ">="
@@ -151,7 +165,7 @@ dependencies:
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
- name: byebug
168
+ name: pry-byebug
155
169
  requirement: !ruby/object:Gem::Requirement
156
170
  requirements:
157
171
  - - ">="
@@ -204,11 +218,12 @@ files:
204
218
  - lib/coverband/configuration.rb
205
219
  - lib/coverband/integrations/background.rb
206
220
  - lib/coverband/integrations/middleware.rb
221
+ - lib/coverband/integrations/rack_server_check.rb
207
222
  - lib/coverband/reporters/base.rb
208
223
  - lib/coverband/reporters/console_report.rb
209
224
  - lib/coverband/reporters/simple_cov_report.rb
210
225
  - lib/coverband/reporters/web.rb
211
- - lib/coverband/utils/s3_report_writer.rb
226
+ - lib/coverband/utils/s3_report.rb
212
227
  - lib/coverband/utils/tasks.rb
213
228
  - lib/coverband/version.rb
214
229
  - test/benchmarks/.gitignore
@@ -220,16 +235,19 @@ files:
220
235
  - test/unit/adapters_base_test.rb
221
236
  - test/unit/adapters_file_store_test.rb
222
237
  - test/unit/adapters_redis_store_test.rb
238
+ - test/unit/background_test.rb
223
239
  - test/unit/collectors_coverage_test.rb
224
240
  - test/unit/configuration_test.rb
241
+ - test/unit/coverband_test.rb
225
242
  - test/unit/dog.rb
226
243
  - test/unit/full_stack_test.rb
227
244
  - test/unit/middleware_test.rb
245
+ - test/unit/rack_server_checkout_test.rb
228
246
  - test/unit/reports_base_test.rb
229
247
  - test/unit/reports_console_test.rb
230
248
  - test/unit/reports_simple_cov_test.rb
231
249
  - test/unit/reports_web_test.rb
232
- - test/unit/utils_s3_report_writer_test.rb
250
+ - test/unit/utils_s3_report_test.rb
233
251
  homepage: https://github.com/danmayer/coverband
234
252
  licenses:
235
253
  - MIT
@@ -245,12 +263,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
245
263
  version: '0'
246
264
  required_rubygems_version: !ruby/object:Gem::Requirement
247
265
  requirements:
248
- - - ">="
266
+ - - ">"
249
267
  - !ruby/object:Gem::Version
250
- version: '0'
268
+ version: 1.3.1
251
269
  requirements: []
252
270
  rubyforge_project:
253
- rubygems_version: 2.7.3
271
+ rubygems_version: 2.5.1
254
272
  signing_key:
255
273
  specification_version: 4
256
274
  summary: Rack middleware to help measure production code usage (LOC runtime usage)
@@ -264,13 +282,16 @@ test_files:
264
282
  - test/unit/adapters_base_test.rb
265
283
  - test/unit/adapters_file_store_test.rb
266
284
  - test/unit/adapters_redis_store_test.rb
285
+ - test/unit/background_test.rb
267
286
  - test/unit/collectors_coverage_test.rb
268
287
  - test/unit/configuration_test.rb
288
+ - test/unit/coverband_test.rb
269
289
  - test/unit/dog.rb
270
290
  - test/unit/full_stack_test.rb
271
291
  - test/unit/middleware_test.rb
292
+ - test/unit/rack_server_checkout_test.rb
272
293
  - test/unit/reports_base_test.rb
273
294
  - test/unit/reports_console_test.rb
274
295
  - test/unit/reports_simple_cov_test.rb
275
296
  - test/unit/reports_web_test.rb
276
- - test/unit/utils_s3_report_writer_test.rb
297
+ - test/unit/utils_s3_report_test.rb
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coverband
4
- module Utils
5
- ###
6
- # TODO: this is currently a html report writer
7
- # this should support writing coverage the current method should be fine
8
- # to write every report to S3 and sum them later or use the 2 pass
9
- # method we do for redis if in a background thread
10
- ###
11
- class S3ReportWriter
12
- def initialize(bucket_name, options = {})
13
- @bucket_name = bucket_name
14
- @region = options[:region]
15
- @access_key_id = options[:access_key_id]
16
- @secret_access_key = options[:secret_access_key]
17
- begin
18
- require 'aws-sdk'
19
- rescue StandardError
20
- err_msg = 'coverband requires aws-sdk in order use S3ReportWriter.'
21
- Coverband.configuration.logger.error err_msg
22
- return
23
- end
24
- end
25
-
26
- def persist!
27
- object.put(body: coverage_content)
28
- end
29
-
30
- private
31
-
32
- def coverage_content
33
- version = Gem::Specification.find_by_name('simplecov-html').version.version
34
- File.read("#{SimpleCov.coverage_dir}/index.html").gsub("./assets/#{version}/", '')
35
- rescue StandardError
36
- File.read("#{SimpleCov.coverage_dir}/index.html").to_s.gsub('./assets/0.10.1/', '')
37
- end
38
-
39
- def object
40
- bucket.object('coverband/index.html')
41
- end
42
-
43
- def s3
44
- client_options = {
45
- region: @region,
46
- access_key_id: @access_key_id,
47
- secret_access_key: @secret_access_key
48
- }
49
- resource_options = { client: Aws::S3::Client.new(client_options) }
50
- resource_options = {} if client_options.values.any?(&:nil?)
51
- Aws::S3::Resource.new(resource_options)
52
- end
53
-
54
- def bucket
55
- s3.bucket(@bucket_name)
56
- end
57
- end
58
- end
59
- end
@@ -1,30 +0,0 @@
1
- require File.expand_path('../test_helper', File.dirname(__FILE__))
2
- require 'aws-sdk'
3
-
4
- module Coverband
5
- class S3ReportWriterTest < Test::Unit::TestCase
6
- def html_version
7
- Gem::Specification.find_by_name('simplecov-html').version.version.to_s
8
- rescue StandardError
9
- '0.10.1'
10
- end
11
-
12
- test 'it writes the coverage report to s3' do
13
- s3 = mock('s3_resource')
14
- bucket = mock('bucket')
15
- object = mock('object')
16
- s3.expects(:bucket).with('coverage-bucket').returns(bucket)
17
- bucket.expects(:object).with('coverband/index.html').returns(object)
18
- File.expects(:read).at_least(0).returns("content ./assets/#{html_version}/")
19
- object.expects(:put).with(body: 'content ')
20
- Aws::S3::Resource.expects(:new).returns(s3)
21
-
22
- s3_writer_options = {
23
- region: 'us-west-1',
24
- access_key_id: '',
25
- secret_access_key: ''
26
- }
27
- Coverband::Utils::S3ReportWriter.new('coverage-bucket', s3_writer_options).persist!
28
- end
29
- end
30
- end