coverband 1.3.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +39 -6
  4. data/changes.md +23 -0
  5. data/coverband.gemspec +2 -1
  6. data/lib/coverband.rb +12 -11
  7. data/lib/coverband/adapters/file_store.rb +59 -0
  8. data/lib/coverband/adapters/memory_cache_store.rb +46 -0
  9. data/lib/coverband/adapters/redis_store.rb +101 -0
  10. data/lib/coverband/base.rb +4 -7
  11. data/lib/coverband/baseline.rb +35 -0
  12. data/lib/coverband/configuration.rb +20 -5
  13. data/lib/coverband/reporters/base.rb +150 -0
  14. data/lib/coverband/reporters/console_report.rb +17 -0
  15. data/lib/coverband/reporters/simple_cov_report.rb +46 -0
  16. data/lib/coverband/s3_report_writer.rb +6 -1
  17. data/lib/coverband/tasks.rb +26 -16
  18. data/lib/coverband/version.rb +1 -1
  19. data/test/benchmarks/benchmark.rake +57 -7
  20. data/test/test_helper.rb +20 -0
  21. data/test/unit/adapters_file_store_test.rb +41 -0
  22. data/test/unit/{memory_cache_store_test.rb → adapters_memory_cache_store_test.rb} +12 -12
  23. data/test/unit/adapters_redis_store_test.rb +164 -0
  24. data/test/unit/base_test.rb +8 -7
  25. data/test/unit/baseline_test.rb +50 -0
  26. data/test/unit/middleware_test.rb +8 -8
  27. data/test/unit/reports_base_test.rb +140 -0
  28. data/test/unit/reports_console_test.rb +37 -0
  29. data/test/unit/reports_simple_cov_test.rb +68 -0
  30. data/test/unit/s3_report_writer_test.rb +1 -0
  31. metadata +37 -24
  32. data/lib/coverband/memory_cache_store.rb +0 -42
  33. data/lib/coverband/redis_store.rb +0 -57
  34. data/lib/coverband/reporter.rb +0 -223
  35. data/test/unit/redis_store_test.rb +0 -107
  36. data/test/unit/reporter_test.rb +0 -207
@@ -0,0 +1,37 @@
1
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
2
+
3
+ class SimpleCovReportTest < Test::Unit::TestCase
4
+ BASE_KEY = Coverband::Adapters::RedisStore::BASE_KEY
5
+
6
+ def setup
7
+ @fake_redis = fake_redis
8
+ @store = Coverband::Adapters::RedisStore.new(@fake_redis, array: true)
9
+ end
10
+
11
+ test "report data" do
12
+ Coverband.configure do |config|
13
+ config.redis = @fake_redis
14
+ config.reporter = 'std_out'
15
+ end
16
+
17
+ Coverband::Reporters::ConsoleReport.expects(:current_root).returns('/tmp/root_dir')
18
+ @fake_redis.expects(:smembers).with(BASE_KEY).returns(fake_coverband_members)
19
+
20
+ fake_coverband_members.each do |key|
21
+ File.expects(:exists?).with(key).returns(true)
22
+ File.expects(:foreach).with(key).returns(Array.new(4){'LOC'})
23
+ @fake_redis.expects(:smembers).with("#{BASE_KEY}.#{key}").returns(["1", "3"])
24
+ end
25
+
26
+ Coverband.configuration.logger.stubs('info')
27
+
28
+ report = Coverband::Reporters::ConsoleReport.report(@store)
29
+ expected = {"/Users/danmayer/projects/hearno/app/controllers/application_controller.rb"=>
30
+ [1, nil, 1, nil],
31
+ "/Users/danmayer/projects/hearno/app/models/account.rb"=>[1, nil, 1, nil],
32
+ "/Users/danmayer/projects/hearno/script/tester.rb"=>[1, nil, 1, nil]}
33
+
34
+ assert_equal(expected, report)
35
+ end
36
+
37
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path('../test_helper', File.dirname(__FILE__))
2
+
3
+ class ReportsSimpleCovTest < Test::Unit::TestCase
4
+ BASE_KEY = Coverband::Adapters::RedisStore::BASE_KEY
5
+
6
+ def setup
7
+ @fake_redis = fake_redis
8
+ @store = Coverband::Adapters::RedisStore.new(@fake_redis, array: true)
9
+ end
10
+
11
+ test "generate scov report" do
12
+ Coverband.configure do |config|
13
+ config.redis = @fake_redis
14
+ config.reporter = 'scov'
15
+ config.s3_bucket = nil
16
+ config.ignore = ["notsomething.rb"]
17
+ end
18
+
19
+ Coverband::Reporters::SimpleCovReport.expects(:current_root).at_least_once.returns('/tmp/root_dir')
20
+ @fake_redis.expects(:smembers).with(BASE_KEY).returns(fake_coverband_members)
21
+
22
+ SimpleCov.expects(:track_files)
23
+ SimpleCov.expects(:add_not_loaded_files).returns({})
24
+ SimpleCov::Result.any_instance.expects(:format!)
25
+ SimpleCov.stubs(:root)
26
+
27
+ fake_coverband_members.each do |key|
28
+ File.expects(:exists?).with(key).returns(true)
29
+ File.expects(:foreach).with(key).returns(Array.new(60){'LOC'})
30
+ @fake_redis.expects(:smembers).with("#{BASE_KEY}.#{key}").returns(["54", "55"])
31
+ end
32
+
33
+ Coverband.configuration.logger.stubs('info')
34
+
35
+ Coverband::Reporters::SimpleCovReport.report(@store, open_report: false)
36
+ end
37
+
38
+ test "generate scov report with additional data" do
39
+ Coverband.configure do |config|
40
+ config.redis = @fake_redis
41
+ config.reporter = 'scov'
42
+ config.s3_bucket = nil
43
+ config.ignore = ["notsomething.rb"]
44
+ end
45
+
46
+ Coverband::Reporters::SimpleCovReport.expects(:current_root).at_least_once.returns('/tmp/root_dir')
47
+ @fake_redis.expects(:smembers).with(BASE_KEY).returns(fake_coverband_members)
48
+
49
+ SimpleCov.expects(:track_files)
50
+ SimpleCov.expects(:add_not_loaded_files).returns({"fake_file.rb" => [1]})
51
+ SimpleCov::Result.any_instance.expects(:format!)
52
+ SimpleCov.stubs(:root)
53
+
54
+ fake_coverband_members.each do |key|
55
+ File.expects(:exists?).with(key).returns(true)
56
+ File.expects(:foreach).with(key).returns(['a','b','c'])
57
+ @fake_redis.expects(:smembers).with("#{BASE_KEY}.#{key}").returns(["54", "55"])
58
+ end
59
+
60
+ Coverband.configuration.logger.stubs('info')
61
+ additional_data = [
62
+ fake_coverage_report
63
+ ]
64
+
65
+ Coverband::Reporters::SimpleCovReport.report(@store, open_report: false, additional_scov_data: additional_data)
66
+ end
67
+
68
+ end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path('../test_helper', File.dirname(__FILE__))
2
+ require 'aws-sdk'
2
3
 
3
4
  module Coverband
4
5
 
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: 1.3.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-27 00:00:00.000000000 Z
11
+ date: 2017-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -123,21 +123,21 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: simplecov
126
+ name: aws-sdk
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :runtime
131
+ version: '2'
132
+ type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '2'
139
139
  - !ruby/object:Gem::Dependency
140
- name: json
140
+ name: simplecov
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
@@ -151,7 +151,7 @@ dependencies:
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
153
  - !ruby/object:Gem::Dependency
154
- name: redis
154
+ name: json
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - ">="
@@ -165,19 +165,19 @@ dependencies:
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
- name: aws-sdk
168
+ name: redis
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - "~>"
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: '2'
173
+ version: '0'
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - "~>"
178
+ - - ">="
179
179
  - !ruby/object:Gem::Version
180
- version: '2'
180
+ version: '0'
181
181
  description: Rack middleware to help measure production code usage (LOC runtime usage)
182
182
  email:
183
183
  - dan@mayerdan.com
@@ -192,16 +192,21 @@ files:
192
192
  - LICENSE.txt
193
193
  - README.md
194
194
  - Rakefile
195
+ - changes.md
195
196
  - coverband.gemspec
196
197
  - docs/coverband_details.png
197
198
  - docs/coverband_index.png
198
199
  - lib/coverband.rb
200
+ - lib/coverband/adapters/file_store.rb
201
+ - lib/coverband/adapters/memory_cache_store.rb
202
+ - lib/coverband/adapters/redis_store.rb
199
203
  - lib/coverband/base.rb
204
+ - lib/coverband/baseline.rb
200
205
  - lib/coverband/configuration.rb
201
- - lib/coverband/memory_cache_store.rb
202
206
  - lib/coverband/middleware.rb
203
- - lib/coverband/redis_store.rb
204
- - lib/coverband/reporter.rb
207
+ - lib/coverband/reporters/base.rb
208
+ - lib/coverband/reporters/console_report.rb
209
+ - lib/coverband/reporters/simple_cov_report.rb
205
210
  - lib/coverband/s3_report_writer.rb
206
211
  - lib/coverband/s3_web.rb
207
212
  - lib/coverband/tasks.rb
@@ -211,13 +216,17 @@ files:
211
216
  - test/benchmarks/dog.rb
212
217
  - test/fake_app/basic_rack.rb
213
218
  - test/test_helper.rb
219
+ - test/unit/adapters_file_store_test.rb
220
+ - test/unit/adapters_memory_cache_store_test.rb
221
+ - test/unit/adapters_redis_store_test.rb
214
222
  - test/unit/base_test.rb
223
+ - test/unit/baseline_test.rb
215
224
  - test/unit/configuration_test.rb
216
225
  - test/unit/dog.rb
217
- - test/unit/memory_cache_store_test.rb
218
226
  - test/unit/middleware_test.rb
219
- - test/unit/redis_store_test.rb
220
- - test/unit/reporter_test.rb
227
+ - test/unit/reports_base_test.rb
228
+ - test/unit/reports_console_test.rb
229
+ - test/unit/reports_simple_cov_test.rb
221
230
  - test/unit/s3_report_writer_test.rb
222
231
  - test/unit/s3_web_test.rb
223
232
  homepage: https://github.com/danmayer/coverband
@@ -250,12 +259,16 @@ test_files:
250
259
  - test/benchmarks/dog.rb
251
260
  - test/fake_app/basic_rack.rb
252
261
  - test/test_helper.rb
262
+ - test/unit/adapters_file_store_test.rb
263
+ - test/unit/adapters_memory_cache_store_test.rb
264
+ - test/unit/adapters_redis_store_test.rb
253
265
  - test/unit/base_test.rb
266
+ - test/unit/baseline_test.rb
254
267
  - test/unit/configuration_test.rb
255
268
  - test/unit/dog.rb
256
- - test/unit/memory_cache_store_test.rb
257
269
  - test/unit/middleware_test.rb
258
- - test/unit/redis_store_test.rb
259
- - test/unit/reporter_test.rb
270
+ - test/unit/reports_base_test.rb
271
+ - test/unit/reports_console_test.rb
272
+ - test/unit/reports_simple_cov_test.rb
260
273
  - test/unit/s3_report_writer_test.rb
261
274
  - test/unit/s3_web_test.rb
@@ -1,42 +0,0 @@
1
- module Coverband
2
- class MemoryCacheStore
3
-
4
- attr_accessor :store
5
-
6
-
7
- def self.files_cache
8
- @files_cache ||= Hash.new
9
- end
10
-
11
- def self.reset!
12
- files_cache.clear
13
- end
14
-
15
- def initialize(store)
16
- @store = store
17
- end
18
-
19
- def store_report files
20
- filtered_files = filter(files)
21
- store.store_report(filtered_files) if filtered_files.any?
22
- end
23
-
24
- private
25
-
26
- def files_cache
27
- self.class.files_cache
28
- end
29
-
30
- def filter(files)
31
- files.each_with_object(Hash.new) do |(file, lines), filtered_file_hash|
32
- #first time we see a file, we pre-init the in memory cache to whatever is in store(redis)
33
- line_cache = files_cache[file] ||= Set.new(store.covered_lines_for_file(file))
34
- lines.reject! do |line|
35
- line_cache.include?(line) ? true : (line_cache << line and false)
36
- end
37
- filtered_file_hash[file] = lines if lines.any?
38
- end
39
- end
40
-
41
- end
42
- end
@@ -1,57 +0,0 @@
1
- module Coverband
2
- class RedisStore
3
- def initialize(redis)
4
- @redis = redis
5
- @_sadd_supports_array = recent_gem_version? && recent_server_version?
6
- end
7
-
8
- def store_report(report)
9
- redis.pipelined do
10
- store_array('coverband', report.keys)
11
-
12
- report.each do |file, lines|
13
- store_array("coverband.#{file}", lines.keys)
14
- end
15
- end
16
- end
17
-
18
-
19
- def covered_lines_for_file(file)
20
- @redis.smembers("coverband.#{file}").map(&:to_i)
21
- end
22
-
23
-
24
- def sadd_supports_array?
25
- @_sadd_supports_array
26
- end
27
-
28
- private
29
-
30
- attr_reader :redis
31
-
32
- def store_array(key, values)
33
- if sadd_supports_array?
34
- redis.sadd(key, values) if (values.length > 0)
35
- else
36
- values.each do |value|
37
- redis.sadd(key, value)
38
- end
39
- end
40
- values
41
- end
42
-
43
- def recent_server_version?
44
- info_data = redis.info
45
- if info_data.is_a?(Hash)
46
- Gem::Version.new(info_data['redis_version']) >= Gem::Version.new('2.4')
47
- else
48
- #guess supported
49
- true
50
- end
51
- end
52
-
53
- def recent_gem_version?
54
- Gem::Version.new(Redis::VERSION) >= Gem::Version.new('3.0')
55
- end
56
- end
57
- end
@@ -1,223 +0,0 @@
1
- module Coverband
2
- class Reporter
3
-
4
- def self.baseline
5
- require 'coverage'
6
- Coverage.start
7
- yield
8
- @project_directory = File.expand_path(Coverband.configuration.root)
9
- results = Coverage.result
10
- results = results.reject { |key, val| !key.match(@project_directory) || Coverband.configuration.ignore.any? { |pattern| key.match(/#{pattern}/) } }
11
-
12
- if Coverband.configuration.verbose
13
- Coverband.configuration.logger.info results.inspect
14
- end
15
-
16
- config_dir = File.dirname(Coverband.configuration.baseline_file)
17
- Dir.mkdir config_dir unless File.exists?(config_dir)
18
- File.open(Coverband.configuration.baseline_file, 'w') { |f| f.write(results.to_json) }
19
- end
20
-
21
- def self.report(options = {})
22
- begin
23
- require 'simplecov' if Coverband.configuration.reporter=='scov'
24
- rescue
25
- Coverband.configuration.logger.error "coverband requires simplecov in order to generate a report, when configured for the scov report style."
26
- return
27
- end
28
- redis = Coverband.configuration.redis
29
- roots = get_roots
30
- existing_coverage = Coverband.configuration.coverage_baseline
31
- open_report = options.fetch(:open_report) { true }
32
-
33
- if Coverband.configuration.verbose
34
- Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}"
35
- end
36
-
37
- if Coverband.configuration.reporter == 'scov'
38
- additional_scov_data = options.fetch(:additional_scov_data) { [] }
39
- if Coverband.configuration.verbose
40
- print additional_scov_data
41
- end
42
- report_scov(redis, existing_coverage, additional_scov_data, roots, open_report)
43
- else
44
- lines = redis.smembers('coverband').map{ |key| report_line(redis, key) }
45
- Coverband.configuration.logger.info lines.join("\n")
46
- end
47
- end
48
-
49
- def self.clear_coverage(redis = nil)
50
- redis ||= Coverband.configuration.redis
51
- redis.smembers('coverband').each { |key| redis.del("coverband.#{key}") }
52
- redis.del("coverband")
53
- end
54
-
55
- def self.get_roots
56
- roots = Coverband.configuration.root_paths
57
- roots << "#{current_root}/"
58
- roots
59
- end
60
-
61
- def self.current_root
62
- File.expand_path(Coverband.configuration.root)
63
- end
64
-
65
- private
66
-
67
- def self.fix_file_names(report_hash, roots)
68
- fixed_report = {} #normalize names across servers
69
- report_hash.each_pair do |key, values|
70
- filename = filename_from_key(key, roots)
71
- fixed_report[filename] = values
72
- end
73
- fixed_report
74
- end
75
-
76
- # [0,0,1,0,1]
77
- # [nil,0,1,0,0]
78
- # merge to
79
- # [0,0,1,0,1]
80
- def self.merge_arrays(first, second)
81
- merged = []
82
- longest = first.length > second.length ? first : second
83
-
84
- longest.each_with_index do |line, index|
85
- if first[index] || second[index]
86
- merged[index] = (first[index].to_i + second[index].to_i >= 1 ? 1 : 0)
87
- else
88
- merged[index] = nil
89
- end
90
- end
91
-
92
- merged
93
- end
94
-
95
-
96
- def self.get_current_scov_data(options = {})
97
- additional_scov_data = options.fetch(:additional_scov_data) { [] }
98
-
99
- if (additional_scov_data)
100
- report_scov_with_additional_data(Coverband.configuration.redis, Coverband.configuration.coverage_baseline, additional_scov_data, get_roots)
101
- else
102
- get_current_scov_data_imp(Coverband.configuration.redis, get_roots)
103
- end
104
- end
105
-
106
- def self.get_current_scov_data_imp(redis, roots)
107
- scov_style_report = {}
108
-
109
- redis.smembers('coverband').each do |key|
110
- next if Coverband.configuration.ignore.any?{ |i| key.match(i) }
111
- line_data = line_hash(redis, key, roots)
112
-
113
- if line_data
114
- line_key = line_data.keys.first
115
- previous_line_hash = scov_style_report[line_key]
116
-
117
- if previous_line_hash
118
- line_data[line_key] = merge_arrays(line_data[line_key], previous_line_hash)
119
- end
120
-
121
- scov_style_report.merge!(line_data)
122
- end
123
- end
124
-
125
- scov_style_report = fix_file_names(scov_style_report, roots)
126
- scov_style_report
127
- end
128
-
129
- def self.report_scov_with_additional_data(redis, existing_coverage, additional_scov_data, roots)
130
- scov_style_report = get_current_scov_data_imp redis, roots
131
- existing_coverage = fix_file_names(existing_coverage, roots)
132
- scov_style_report = merge_existing_coverage(scov_style_report, existing_coverage)
133
-
134
- additional_scov_data.each do |data|
135
- scov_style_report = merge_existing_coverage(scov_style_report, data)
136
- end
137
-
138
- scov_style_report
139
- end
140
-
141
- def self.report_scov(redis, existing_coverage, additional_scov_data, roots, open_report)
142
- scov_style_report = report_scov_with_additional_data(redis, existing_coverage, additional_scov_data, roots)
143
-
144
- if Coverband.configuration.verbose
145
- Coverband.configuration.logger.info "report: "
146
- Coverband.configuration.logger.info scov_style_report.inspect
147
- end
148
-
149
- # add in files never hit in coverband
150
- SimpleCov.track_files "#{current_root}/{app,lib,config}/**/*.{rb,haml,erb,slim}"
151
- SimpleCov::Result.new(SimpleCov.add_not_loaded_files(scov_style_report)).format!
152
- if open_report
153
- `open #{SimpleCov.coverage_dir}/index.html`
154
- else
155
- Coverband.configuration.logger.info "report is ready and viewable: open #{SimpleCov.coverage_dir}/index.html"
156
- end
157
- S3ReportWriter.new(Coverband.configuration.s3_bucket).persist! if Coverband.configuration.s3_bucket
158
- end
159
-
160
-
161
- def self.merge_existing_coverage(scov_style_report, existing_coverage)
162
- existing_coverage.each_pair do |key, lines|
163
- if current_lines = scov_style_report[key]
164
- lines.each_with_index do |line, index|
165
- if line.nil? && current_lines[index].to_i == 0
166
- current_lines[index] = nil
167
- else
168
- current_lines[index] = current_lines[index] ? (current_lines[index].to_i + line.to_i) : nil
169
- end
170
- end
171
- scov_style_report[key] = current_lines
172
- else
173
- scov_style_report[key] = lines
174
- end
175
- end
176
- scov_style_report
177
- end
178
-
179
- # /Users/danmayer/projects/cover_band_server/views/index/erb: ["0", "2", "3", "6", "65532", "65533"]
180
- # /Users/danmayer/projects/cover_band_server/app/rb: ["54", "55"]
181
- # /Users/danmayer/projects/cover_band_server/views/layout/erb: ["0", "33", "36", "37", "38", "39", "40", "62", "63", "66", "65532", "65533"]
182
- def self.report_line(redis, key)
183
- "#{key}: #{line_members(redis, key)}"
184
- end
185
-
186
- def self.line_members(redis, key)
187
- redis.smembers("coverband.#{key}").inspect
188
- end
189
-
190
- def self.filename_from_key(key, roots)
191
- filename = key
192
- roots.each do |root|
193
- filename = filename.gsub(/^#{root}/, './')
194
- end
195
- # the filename for SimpleCov is expected to be a full path.
196
- # roots.last should be roots << current_root}/
197
- # a fully expanded path of config.root
198
- filename = filename.gsub('./', roots.last)
199
- filename
200
- end
201
-
202
- # >> puts Coverage.result.inspect
203
- # {"/Users/danmayer/projects/hearno/script/tester.rb"=>[1, nil, 1, 1, nil, nil, nil]}
204
- def self.line_hash(redis, key, roots)
205
- filename = filename_from_key(key, roots)
206
- if File.exists?(filename)
207
- lines_hit = redis.smembers("coverband.#{key}")
208
- count = File.foreach(filename).inject(0) { |c, line| c + 1 }
209
- if filename.match(/\.erb/)
210
- line_array = Array.new(count, nil)
211
- else
212
- line_array = Array.new(count, 0)
213
- end
214
- line_array.each_with_index{|line,index| line_array[index] = 1 if lines_hit.include?((index + 1).to_s) }
215
- {filename => line_array}
216
- else
217
- Coverband.configuration.logger.info "file #{filename} not found in project"
218
- nil
219
- end
220
- end
221
-
222
- end
223
- end