coverband 3.0.0 → 3.0.1.alpha

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
- 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