coverband 2.0.1 → 2.0.2.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
2
  SHA1:
3
- metadata.gz: a3885791f4771973082ff809237d3a15a7f397ed
4
- data.tar.gz: 158d669d609287e94b50b12d71811ca3252d80ee
3
+ metadata.gz: d86abf13125588b12cb567afcf59f8289cb4bd1c
4
+ data.tar.gz: bda957a57268f3d5a74ea6ffe8502146edf2c4bb
5
5
  SHA512:
6
- metadata.gz: c252116c4add56d46c26662dbebf90d03ba40de023dbb67250f69c92a72037f7a8c0d3e2a4a075f365f2f6c4be5306d1fe0a2328e03d684be615d3d2a922272c
7
- data.tar.gz: 51988a04b8b22d8181beeaf209bf320c9bdfd042e427de59b9caa8902f3f9792569451454489961c290105a67e2e0e40efcc2684d10aabaea6114c3e41ae8215
6
+ metadata.gz: 599dbb24f2292684fe9418352e1564ffa13cebcb5c3ff5831f90d0ad86496b00ec4f1e16c33f1f38c2f96a098553422bb2e44af263bd4c7379ab4ecee045dcd0
7
+ data.tar.gz: 013454ba197354052f8fa8ce933a7a669761b685299e7e3657895b370201b166837961dc92c81fb4068c2dc5333abad89625e080fbf6454001621992ee05e9ed
data/.gitignore CHANGED
@@ -18,4 +18,5 @@ spec/reports
18
18
  test/tmp
19
19
  test/version_tmp
20
20
  tmp
21
- .byebug_history
21
+ .byebug_history
22
+ .env
data/README.md CHANGED
@@ -4,6 +4,7 @@ Build Status: [![Build Status](https://travis-ci.org/danmayer/coverband.svg?bran
4
4
 
5
5
  <p align="center">
6
6
  <a href="#key-features">Key Features</a> •
7
+ <a href="#coverband-demo">Coverband Demo</a> •
7
8
  <a href="#how-to-use">How To Use</a> •
8
9
  <a href="#installation">Installation</a> •
9
10
  <a href="#configuration">Configuration</a> •
@@ -17,24 +18,31 @@ Note: Coverband is not intended for test code coverage, for that just check out
17
18
 
18
19
  ## Key Features
19
20
 
20
- * Allows sampling to avoid the performance overhead on every request.
21
+ The primary goal of Coverband is giving deep insight into your production runtime usage of your application code, while having the least impact on performance possible.
22
+
23
+ * Low performance overhead
24
+ * Various controls from sampling, data collection rate, etc to further control performance
21
25
  * Ignore directories to avoid overhead data collection on vendor, lib, etc.
22
- * Take a baseline to get initial app execution during app initialization. (the baseline is important because some code is executed during app load, but might not be invoked during any requests, think prefetching, initial cache builds, setting constants, etc...)
23
- * Development mode for additional code usage details (number of LOC execution during single request, etc).
26
+ * Development mode, offers deep insight of code usage details (number of LOC execution during single request, etc) during development.
27
+ * Easy setup for any Ruby Rack based web framework (Rails, Sinatra, etc)
28
+ * Allows for integration with any other Ruby application flows (background jobs, crons, scripts)
29
+
30
+ ## Coverband Demo
31
+
32
+ Take Coverband for a spin on the live Heroku deployed [Coverband Demo](https://coverband-demo.herokuapp.com/). The [full source code for the demo](https://github.com/danmayer/coverband_demo) is available to help with configuration and understanding of basic usage.
24
33
 
25
34
  # How To Use
26
35
 
27
36
  Below is my Coverband workflow, which hopefully will help other best use this library.
28
37
 
29
- * install coverband.
30
- * take baseline measurment: `rake coverband:baseline` (__note: never run baseline on production__)
31
- * validate baseline with `rake coverband:coverage`
38
+ * install coverband
39
+ * start your app and hit a few endpoints
40
+ * validate data collection and code coverage with `rake coverband:coverage`
32
41
  * test setup in development (hit endpoints and generate new report)
33
42
  * deploy to staging and verify functionality
34
43
  * deploy to production and verify functionality
35
- * every 2 weeks or with major releases
44
+ * every 2 weeks or so, with major releases
36
45
  * clear old coverage: `rake coverband:clear`
37
- * take new baseline: `rake coverband:baseline`
38
46
  * deploy and verify coverage is matching expectations
39
47
  * __COVERAGE DRIFT__
40
48
  * if you never clear you have lines of code drift from when they were recorded
@@ -138,8 +146,7 @@ require 'coverband/tasks'
138
146
  This should give you access to a number of Coverband tasks
139
147
 
140
148
  ```bash
141
- bundle exec rake -T coverband
142
- rake coverband:baseline # record coverband coverage baseline
149
+ rake -T coverband
143
150
  rake coverband:clear # reset coverband coverage data
144
151
  rake coverband:coverage # report runtime coverband code coverage
145
152
  ```
@@ -194,10 +201,10 @@ run ActionController::Dispatcher.new
194
201
 
195
202
  # Verify Correct Installation
196
203
 
197
- * Gather baseline metrics: run `bundle exec rake coverband:baseline` (__note: never run baseline on production__)
198
- * run `bundle exec rake coverband:coverage` this will show app initialization coverage
204
+ * boot up your application
205
+ * run `rake coverband:coverage` this will show app initialization coverage
199
206
  * run app and hit a controller (hit at least +1 time over your `config.startup_delay` setting default is 0)
200
- * run `bundle exec rake coverband:coverage` and you should see coverage increasing for the endpoints you hit.
207
+ * run `rake coverband:coverage` and you should see coverage increasing for the endpoints you hit.
201
208
 
202
209
  ## Installation Script
203
210
 
@@ -220,7 +227,7 @@ bundle install
220
227
 
221
228
  # Make some code so we can look at the coverage
222
229
  rails generate scaffold blogs
223
- bundle exec rake db:migrate
230
+ rake db:migrate
224
231
 
225
232
  # open Rakefile, add lines
226
233
  require 'coverband'
@@ -233,10 +240,9 @@ rake -T coverband
233
240
  # configure config/application.rb
234
241
  # copy lines from readme
235
242
 
236
-
237
- rake coverband:baseline
243
+ # start up your app
238
244
  rake coverband:coverage
239
- # view baseline coverage
245
+ # view boot up coverage
240
246
 
241
247
  rails s
242
248
 
@@ -256,68 +262,14 @@ rake coverband:coverage
256
262
  - [Sinatra app](https://github.com/danmayer/churn-site)
257
263
  - [Non Rack Ruby app](https://github.com/danmayer/coverband_examples)
258
264
 
259
- ### Coverband Baseline
260
-
261
- __TLDR:__ Baseline is app initialization coverage, not captured during runtime.
262
-
263
- Before starting a service verify your baseline by running `rake coverband:baseline` followed by `rake coverband:coverage` to view what your baseline coverage looks like before any runtime traffic has been recorded.
264
-
265
- The baseline seems to cause some confusion. Basically, when Coverband records code usage, it will not request initial startup code like method definition, it covers what it hit during run time. This would produce a fairly odd view of code usage. To cover things like defining routes, dynamic methods, and the like Coverband records a baseline. The baseline should capture coverage of app initialization and boot up, we don't want to do this on deploy as it can be slow. So we take a recording of boot up as a one time baseline Rake task `bundle exec rake coverband:baseline`.
266
-
267
- 1. Start your server with `rails s` or `rackup config.ru`.
268
- 2. Hit your development server exercising the endpoints you want to verify Coverband is recording (you should see debug outputs in your server console)
269
- 3. Run `rake coverband:coverage` again, previously it should have only shown the baseline data of your app initializing. After using it in development it should show increased coverage from the actions you have exercised.
270
-
271
- Note: if you use `rails s` and data isn't recorded, make sure it is using your `config.ru`.
272
-
273
- ### Baseline Missing data
274
-
275
- The default Coverband baseline task will try to detect your app as either Rack or Rails environment. It will load the app to take a baseline reading. The baseline coverage is important because some code is executed during app load, but might not be invoked during any requests, think prefetching, initial cache builds, setting constants, etc. If the baseline task doesn't load your app well you can override the default baseline to create a better baseline yourself. Below for example is how I take a baseline on a pretty simple Sinatra app.
276
-
277
- ```ruby
278
- namespace :coverband do
279
- desc "get coverage baseline"
280
- task :baseline_app do
281
- Coverband::Reporter.baseline {
282
- require 'sinatra'
283
- require './app.rb'
284
- }
285
- end
286
- end
287
- ```
288
-
289
265
  ### View Coverage
290
266
 
291
267
  You can view the report different ways, but the easiest is the Rake task which opens the SimpleCov formatted HTML.
292
268
 
293
- `bundle exec rake coverband:coverage`
269
+ `rake coverband:coverage`
294
270
 
295
271
  This should auto-open in your browser, but if it doesn't the output file should be in `coverage/index.html`
296
272
 
297
- ### Conflicting .Simplecov: Issue with Missing or 0% Coverage Report
298
-
299
- If you use SimpleCov to generate code coverage for your tests. You might have setup a `.simplecov` file to help control and focus it's output. Often the settings you want for your test's code coverage report are different than what you want Coverband to be reporting on. Since Coverband uses the SimpleCov HTML formatter to prepare it's report.
300
-
301
- So if you had something like this in a `.simplecov` file in the root of your project, as reported in [issue 83](https://github.com/danmayer/coverband/issues/83)
302
-
303
- ```
304
- require 'simplecov'
305
-
306
- SimpleCov.start do
307
- add_filter 'app/admin'
308
- add_filter '/spec/'
309
- add_filter '/config/'
310
- add_filter '/vendor/'
311
- add_filter 'userevents'
312
- end
313
- ```
314
-
315
- You could see some confusing results... To avoid this issue Coverband has a Rake task that will ignore all Simplecov filters.
316
-
317
- `rake coverband:coverage_no_filters`
318
-
319
- This will build the report after disabling any `.simplecov` applied settings.
320
-
321
273
  ### Clear Coverage
322
274
 
323
275
  If your code has changed and your coverage line data doesn't seem to match run time. You probably need to clear your old line data... You will need to run this in the environment you wish to clear the data from.
@@ -525,7 +477,7 @@ Beyond writing to S3 you can host the S3 file with a build in Sintatra app in Co
525
477
  ```
526
478
  Rails.application.routes.draw do
527
479
  # ... lots of routes
528
- mount Coverband::S3Web, at: '/coverage'
480
+ mount Coverband::Reporters::Web.new, at: '/coverage'
529
481
  end
530
482
  ```
531
483
 
@@ -554,11 +506,35 @@ end
554
506
  Rails.application.routes.draw do
555
507
  # ... lots of routes
556
508
  constraints basic_constraint do
557
- mount Coverband::S3Web, at: '/coverage'
509
+ mount Coverband::Reporters::Web.new, at: '/coverage'
558
510
  end
559
511
  end
560
512
  ```
561
513
 
514
+ ### Conflicting .Simplecov: Issue with Missing or 0% Coverage Report
515
+
516
+ If you use SimpleCov to generate code coverage for your tests. You might have setup a `.simplecov` file to help control and focus it's output. Often the settings you want for your test's code coverage report are different than what you want Coverband to be reporting on. Since Coverband uses the SimpleCov HTML formatter to prepare it's report.
517
+
518
+ So if you had something like this in a `.simplecov` file in the root of your project, as reported in [issue 83](https://github.com/danmayer/coverband/issues/83)
519
+
520
+ ```
521
+ require 'simplecov'
522
+
523
+ SimpleCov.start do
524
+ add_filter 'app/admin'
525
+ add_filter '/spec/'
526
+ add_filter '/config/'
527
+ add_filter '/vendor/'
528
+ add_filter 'userevents'
529
+ end
530
+ ```
531
+
532
+ You could see some confusing results... To avoid this issue Coverband has a Rake task that will ignore all Simplecov filters.
533
+
534
+ `rake coverband:coverage_no_filters`
535
+
536
+ This will build the report after disabling any `.simplecov` applied settings.
537
+
562
538
  # Contributing To Coverband
563
539
 
564
540
  If you are working on adding features, PRs, or bugfixes to Coverband this section should help get you going.
@@ -567,24 +543,24 @@ If you are working on adding features, PRs, or bugfixes to Coverband this sectio
567
543
  2. Create your feature branch (`git checkout -b my-new-feature`)
568
544
  3. Commit your changes (`git commit -am 'Add some feature'`)
569
545
  4. Push to the branch (`git push origin my-new-feature`)
570
- 5. Make sure all tests are passing (run `bundle install`, make sure Redis is running, and then execute `bundle exec rake test`)
546
+ 5. Make sure all tests are passing (run `bundle install`, make sure Redis is running, and then execute `rake test`)
571
547
  6. Create new Pull Request
572
548
 
573
549
  ### Tests & Benchmarks
574
550
 
575
551
  If you submit a change please make sure the tests and benchmarks are passing.
576
552
 
577
- * run tests: `bundle exec rake`
553
+ * run tests: `rake`
578
554
  * view test coverage: `open coverage/index.html`
579
555
  * run the benchmarks before and after your change to see impact
580
- * `bundle exec rake benchmarks`
556
+ * `rake benchmarks`
581
557
 
582
558
  ### Known Issues
583
559
 
584
560
  * __total fail__ on front end code, because of the precompiled template step basically coverage doesn't work well for `erb`, `slim`, and the like.
585
561
  * related it will try to report something, but the line numbers reported for `ERB` files are often off and aren't considered useful. I recommend filtering out .erb using the `config.ignore` option.
586
562
  * If you have SimpleCov filters, you need to clear them prior to generating your coverage report. As the filters will be applied to Coverband as well and can often filter out everything we are recording.
587
- * coverage doesn't show for Rails `config/application.rb` or `config/boot.rb` as they get loaded when loading the Rake environment prior to starting to record the baseline.
563
+ * coverage doesn't show for Rails `config/application.rb` or `config/boot.rb` as they get loaded when loading the Rake environment prior to starting the `Coverage` library.
588
564
 
589
565
  ### Debugging Redis Store
590
566
 
@@ -655,20 +631,20 @@ Similar format to redis store, but array with integer values
655
631
 
656
632
  ### Todo
657
633
 
658
- * Sinatra App with admin controls
634
+ * rackup / how to run webapp via rake
635
+ * move off sinatra to pure rack
659
636
  * graphite adapters (it would allow passing in date ranges on usage)
660
637
  * perf test for array vs hash
661
638
  * redis pipeline around hash (or batch get then push)
662
- * pass in namespace to redis (coverage vs baseline)
663
- * what about having baseline a onetime recording into redis no merge later
664
639
  * move to SimpleCov console out, or make similar console tabular output
665
- * Fix network performance by logging to files that purge later (like NR) (far more time lost in TracePoint than sending files, hence not a high priority, but would be cool)
640
+ * Improve network performance by logging to files that purge later (like NR) (far more time lost in TracePoint than sending files, hence not a high priority, but would be cool)
666
641
  * Add support for [zadd](http://redis.io/topics/data-types-intro) so one could determine single call versus multiple calls on a line, letting us determine the most executed code in production.
667
642
  * Possibly add ability to record code run for a given route
643
+ * integrate recording with deploy tag or deploy timestamp
644
+ * diff code usage across deployed versions
668
645
  * Improve client code api, around manual usage of sampling (like event usage)
669
646
  * ability to change the Coverband config at runtime by changing the config pushed to the Redis hash. In memory cache around the changes to only make that call periodically.
670
647
  * Opposed to just showing code usage on a route allow 'tagging' events which would record line coverage for that tag (this would allow tagging all code that modified an ActiveRecord model for example
671
- * mountable rack app to view coverage similar to flipper-ui
672
648
  * support runner, active job, etc without needed extra config (improved railtie integration)
673
649
 
674
650
  # Resources
data/Rakefile CHANGED
@@ -19,3 +19,10 @@ desc 'load irb with this gem'
19
19
  task :console do
20
20
  exec 'irb -I lib -r coverband'
21
21
  end
22
+
23
+ # This is really just for testing and development because without configuration
24
+ # Coverband can't do much
25
+ desc 'start webserver'
26
+ task :server do
27
+ exec 'rackup -I lib'
28
+ end
data/changes.md CHANGED
@@ -14,6 +14,18 @@ Will be the fully modern release that drops maintenance legacy support in favor
14
14
  * built in support for activejob, sidekiq, and other common frameworks
15
15
  * code route tracing (entry point to all code executed for example /some_path -> code coverage of that path)
16
16
 
17
+ # Alpha
18
+
19
+ ### 2.0.2
20
+
21
+ * fix possible nil error on files that changed since initial recording @viktor-silakov
22
+ * add improve error logging in verbose mode (stacktrace) @viktor-silakov
23
+ * improved logging level support @viktor-silakov
24
+ * launch Coverband demo and integrate into Readme / Documentation
25
+ * fix on baseline to show an issue by @viktor-silakov
26
+ * remove all coverband:baseline related features and documentation
27
+ * dropped Sinatra requirement for web mountable page
28
+
17
29
  # Released
18
30
 
19
31
  ### 2.0.1
data/config.ru ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require ::File.expand_path('../lib/coverband', __FILE__)
4
+ run Coverband::Reporters::Web.new
data/coverband.gemspec CHANGED
@@ -26,7 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'rack'
27
27
  spec.add_development_dependency 'rack-test'
28
28
  spec.add_development_dependency 'rake'
29
- spec.add_development_dependency 'sinatra'
30
29
  spec.add_development_dependency 'test-unit'
31
30
  spec.add_development_dependency 'redis'
32
31
  spec.add_development_dependency 'benchmark-ips'
data/lib/coverband.rb CHANGED
@@ -12,10 +12,10 @@ require 'coverband/adapters/file_store'
12
12
  require 'coverband/collectors/base'
13
13
  require 'coverband/collectors/trace'
14
14
  require 'coverband/collectors/coverage'
15
- require 'coverband/baseline'
16
15
  require 'coverband/reporters/base'
17
16
  require 'coverband/reporters/simple_cov_report'
18
17
  require 'coverband/reporters/console_report'
18
+ require 'coverband/reporters/web'
19
19
  require 'coverband/middleware'
20
20
  require 'coverband/s3_report_writer'
21
21
 
@@ -87,7 +87,7 @@ module Coverband
87
87
  end
88
88
 
89
89
  def output_file_line_usage
90
- @logger.info 'coverband debug coverband file:line usage:'
90
+ @logger.debug 'coverband debug coverband file:line usage:'
91
91
  @file_line_usage.sort_by { |_key, value| value.length }.each do |pair|
92
92
  file = pair.first
93
93
  lines = pair.last
@@ -18,7 +18,7 @@ module Coverband
18
18
  end
19
19
 
20
20
  if failed_recently?
21
- @logger.info 'coverage reporting standing-by because of recent failure' if @verbose
21
+ @logger.error 'coverage reporting standing-by because of recent failure' if @verbose
22
22
  return
23
23
  end
24
24
 
@@ -31,7 +31,7 @@ module Coverband
31
31
  end
32
32
 
33
33
  if @verbose
34
- @logger.info "coverband file usage: #{file_usage.inspect}"
34
+ @logger.debug "coverband file usage: #{file_usage.inspect}"
35
35
  output_file_line_usage if @verbose == 'debug'
36
36
  end
37
37
 
@@ -39,8 +39,8 @@ module Coverband
39
39
  @store.save_report(@file_line_usage)
40
40
  @file_line_usage.clear
41
41
  elsif @verbose
42
- @logger.info 'coverage report: '
43
- @logger.info @file_line_usage.inspect
42
+ @logger.debug 'coverage report: '
43
+ @logger.debug @file_line_usage.inspect
44
44
  end
45
45
  # StandardError might be better option
46
46
  # coverband previously had RuntimeError here
@@ -49,15 +49,16 @@ module Coverband
49
49
  rescue StandardError => err
50
50
  failed!
51
51
  if @verbose
52
- @logger.info 'coverage missing'
53
- @logger.info "error: #{err.inspect} #{err.message}"
52
+ @logger.error 'coverage missing'
53
+ @logger.error "error: #{err.inspect} #{err.message}"
54
+ @logger.error err.backtrace
54
55
  end
55
56
  end
56
57
 
57
58
  private
58
59
 
59
60
  def array_diff(latest, original)
60
- latest.map.with_index { |v, i| v ? v - original[i] : nil }
61
+ latest.map.with_index { |v, i| (v && original[i]) ? v - original[i] : nil }
61
62
  end
62
63
 
63
64
  def previous_results
@@ -2,8 +2,16 @@
2
2
 
3
3
  module Coverband
4
4
  module Collectors
5
+ ###
6
+ # NOTE: While this still works it is slower than Coverage.
7
+ # I recommend using the Coverage adapter.
8
+ # As baseline is removed the Trace collector also doesn't have a good way
9
+ # to collect initial code usage during app boot up.
10
+ #
11
+ # I am leaving Trace around as I believe there are some interesting use cases
12
+ # also, it illustrates an alternative collector, and I have some others I would like to implement
13
+ ###
5
14
  class Trace < Base
6
-
7
15
  def reset_instance
8
16
  super
9
17
  @tracer_set = false
@@ -21,8 +29,9 @@ module Coverband
21
29
  rescue RuntimeError => err
22
30
  failed!
23
31
  if @verbose
24
- @logger.info 'error stating recording coverage'
25
- @logger.info "error: #{err.inspect} #{err.message}"
32
+ @logger.error 'error stating recording coverage'
33
+ @logger.error "error: #{err.inspect} #{err.message}"
34
+ @logger.error err.backtrace
26
35
  end
27
36
  end
28
37
 
@@ -39,12 +48,12 @@ module Coverband
39
48
  unset_tracer
40
49
 
41
50
  if failed_recently?
42
- @logger.info 'coverage reporting standing-by because of recent failure' if @verbose
51
+ @logger.error 'coverage reporting standing-by because of recent failure' if @verbose
43
52
  return
44
53
  end
45
54
 
46
55
  if @verbose
47
- @logger.info "coverband file usage: #{file_usage.inspect}"
56
+ @logger.debug "coverband file usage: #{file_usage.inspect}"
48
57
  output_file_line_usage if @verbose == 'debug'
49
58
  end
50
59
 
@@ -58,8 +67,9 @@ module Coverband
58
67
  rescue RuntimeError => err
59
68
  failed!
60
69
  if @verbose
61
- @logger.info 'coverage missing'
62
- @logger.info "error: #{err.inspect} #{err.message}"
70
+ @logger.error 'coverage missing'
71
+ @logger.error "error: #{err.inspect} #{err.message}"
72
+ @logger.error err.backtrace
63
73
  end
64
74
  end
65
75
 
@@ -9,13 +9,13 @@ module Coverband
9
9
 
10
10
  if Coverband.configuration.verbose
11
11
  Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}"
12
- Coverband.configuration.logger.info "additional data:\n #{additional_coverage_data}"
12
+ Coverband.configuration.logger.debug "additional data:\n #{additional_coverage_data}"
13
13
  end
14
14
 
15
15
  scov_style_report = report_scov_with_additional_data(store, additional_coverage_data, roots)
16
16
 
17
17
  if Coverband.configuration.verbose
18
- Coverband.configuration.logger.info "report:\n #{scov_style_report.inspect}"
18
+ Coverband.configuration.logger.debug "report:\n #{scov_style_report.inspect}"
19
19
  end
20
20
  scov_style_report
21
21
  end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack'
4
+
5
+ module Coverband
6
+ module Reporters
7
+ # TODO: move to reports and drop need for S3 allow reading from adapters?
8
+ class Web
9
+ attr_reader :request
10
+
11
+ def initialize
12
+ @static = Rack::Static.new(self,
13
+ root: File.expand_path('public', Gem::Specification.find_by_name('simplecov-html').full_gem_path),
14
+ urls: [/.*\.css/, /.*\.js/, /.*\.gif/, /.*\.png/]
15
+ )
16
+ end
17
+
18
+ def call(env)
19
+ @request = Rack::Request.new(env)
20
+
21
+ if request.post?
22
+ case request.path_info
23
+ when /\/clear/
24
+ clear
25
+ when /\/update_report/
26
+ update_report
27
+ when /\/collect_coverage/
28
+ collect_coverage
29
+ when /\/reload_files/
30
+ reload_files
31
+ else
32
+ [404, {'Content-Type' => 'text/html'}, ['404 error!']]
33
+ end
34
+ else
35
+ case request.path_info
36
+ when /.*\.(css|js|gif|png)/
37
+ @static.call(env)
38
+ when /\/show/
39
+ [200, {'Content-Type' => 'text/html'}, [show]]
40
+ when /\//
41
+ [200, {'Content-Type' => 'text/html'}, [index]]
42
+ else
43
+ [404, {'Content-Type' => 'text/html'}, ['404 error!']]
44
+ end
45
+ end
46
+ end
47
+
48
+ # todo move to file or template
49
+ def index
50
+ html = "<html>"
51
+ html += "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params['notice'])}<br/>" if request.params['notice']
52
+ html += "<ul>"
53
+ html += "<li><a href='#{base_path}'>Coverband Web Admin Index</a></li>"
54
+ html += "<li><a href='#{base_path}show'>view coverage report</a></li>"
55
+ html += "<li>#{button("#{base_path}collect_coverage",'update coverage data (collect coverage)')}</li>"
56
+ html += "<li>#{button("#{base_path}update_report",'update coverage report (rebuild report)')}</li>"
57
+ html += "<li>#{button("#{base_path}clear",'clear coverage report')}</li>"
58
+ html += "<li>#{button("#{base_path}reload_files",'reload Coverband files')}</li>"
59
+ html += "</ul>"
60
+ html += "<br/>"
61
+ html += "version: #{Coverband::VERSION}<br/>"
62
+ html += "<a href='https://github.com/danmayer/coverband'>Coverband</a>"
63
+ html += "</html>"
64
+ html
65
+ end
66
+
67
+ def show
68
+ html = s3.get_object(bucket: Coverband.configuration.s3_bucket, key: 'coverband/index.html').body.read
69
+ # hack the static HTML assets to link to the path where this was mounted
70
+ html = html.gsub("src='", "src='#{base_path}")
71
+ html = html.gsub("href='", "href='#{base_path}")
72
+ html = html.gsub("loading.gif", "#{base_path}loading.gif")
73
+ html = html.gsub("/images/", "#{base_path}images/")
74
+ html
75
+ end
76
+
77
+ def update_report
78
+ Coverband::Reporters::SimpleCovReport.report(Coverband.configuration.store, open_report: false)
79
+ notice = 'coverband coverage updated'
80
+ [301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
81
+ end
82
+
83
+ def collect_coverage
84
+ Coverband::Collectors::Base.instance.report_coverage
85
+ notice = 'coverband coverage collected'
86
+ [301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
87
+ end
88
+
89
+ def clear
90
+ Coverband.configuration.store.clear!
91
+ notice = 'coverband coverage cleared'
92
+ [301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
93
+ end
94
+
95
+ def reload_files
96
+ if Coverband.configuration.safe_reload_files
97
+ Coverband.configuration.safe_reload_files.each do |safe_file|
98
+ load safe_file
99
+ end
100
+ end
101
+ # force reload
102
+ Coverband.configure
103
+ notice = 'coverband files reloaded'
104
+ [301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
105
+ end
106
+
107
+ private
108
+
109
+ def button(url, title)
110
+ button = "<form action='#{url}' method='post'>"
111
+ button += "<button type='submit'>#{title}</button>"
112
+ button + '</form>'
113
+ end
114
+
115
+ # This method should get the root mounted endpoint
116
+ # for example if the app is mounted like so:
117
+ # mount Coverband::S3Web, at: '/coverage'
118
+ # "/coverage/collect_coverage?" become:
119
+ # /coverage/
120
+ def base_path
121
+ request.path.match("\/.*\/") ? request.path.match("\/.*\/")[0] : '/'
122
+ end
123
+
124
+ def s3
125
+ begin
126
+ require 'aws-sdk'
127
+ rescue StandardError
128
+ Coverband.configuration.logger.error "coverband requires 'aws-sdk' in order use S3ReportWriter."
129
+ return
130
+ end
131
+ @s3 ||= begin
132
+ client_options = {
133
+ region: Coverband.configuration.s3_region,
134
+ access_key_id: Coverband.configuration.s3_access_key_id,
135
+ secret_access_key: Coverband.configuration.s3_secret_access_key
136
+ }
137
+ client_options = {} if client_options.values.any?(&:nil?)
138
+ Aws::S3::Client.new(client_options)
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # possibly move to / make an adapter or more likely a reporter
3
4
  class S3ReportWriter
4
5
  def initialize(bucket_name, options = {})
5
6
  @bucket_name = bucket_name
@@ -1,52 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :coverband do
4
- def safely_import_files(files_to_cover)
5
- if files_to_cover.any?
6
- files = Coverband::Baseline.exclude_files(files_to_cover)
7
- files.each do |file|
8
- begin
9
- require_dependency file
10
- rescue Exception => err
11
- if Coverband.configuration.verbose
12
- Coverband.configuration.logger.info "error adding file to baseline: #{file}"
13
- Coverband.configuration.logger.info "error: #{err}"
14
- end
15
- end
16
- end
17
- end
18
- end
19
-
20
- desc 'record coverband coverage baseline'
21
- task :baseline do
22
- Coverband::Baseline.record do
23
- if Rake::Task.tasks.any? { |key| key.to_s.match(/environment$/) }
24
- Coverband.configuration.logger.info 'invoking rake environment'
25
- Rake::Task['environment'].invoke
26
- elsif Rake::Task.tasks.any? { |key| key.to_s.match(/env$/) }
27
- Coverband.configuration.logger.info 'invoking rake env'
28
- Rake::Task['env'].invoke
29
- end
30
-
31
- baseline_files = [File.expand_path('./config/boot.rb', Dir.pwd),
32
- File.expand_path('./config/application.rb', Dir.pwd),
33
- File.expand_path('./config/environment.rb', Dir.pwd)]
34
-
35
- baseline_files.each do |baseline_file|
36
- require baseline_file if File.exist?(baseline_file)
37
- end
38
-
39
- safely_import_files(Coverband.configuration.additional_files.flatten)
40
-
41
- if defined? Rails
42
- safely_import_files(Dir.glob("#{Rails.root}/app/**/*.rb"))
43
- if File.exist?("#{Rails.root}/lib")
44
- safely_import_files(Dir.glob("#{Rails.root}/lib/**/*.rb"))
45
- end
46
- end
47
- end
48
- end
49
-
50
4
  ###
51
5
  # note: If your project has set many simplecov filters.
52
6
  # You might want to override them and clear the filters.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coverband
4
- VERSION = '2.0.1'
4
+ VERSION = '2.0.2.alpha'
5
5
  end
data/test/test_helper.rb CHANGED
@@ -59,11 +59,6 @@ end
59
59
 
60
60
  require 'coverband'
61
61
 
62
- unless File.exist?('./tmp/coverband_baseline.json')
63
- `mkdir -p ./tmp`
64
- `touch ./tmp/coverband_baseline.json`
65
- end
66
-
67
62
  Coverband.configure do |config|
68
63
  config.root = Dir.pwd
69
64
  config.root_paths = ['/app/']
@@ -49,6 +49,7 @@ class CollectorsBaseTest < Test::Unit::TestCase
49
49
  coverband.instance_variable_set('@store', nil)
50
50
  assert_equal false, coverband.instance_variable_get('@enabled')
51
51
  logger.expects(:info).at_least_once
52
+ logger.stubs('debug')
52
53
  coverband.sample { 1 + 1 }
53
54
  assert_equal true, coverband.instance_variable_get('@enabled')
54
55
  end
@@ -62,8 +63,8 @@ class CollectorsBaseTest < Test::Unit::TestCase
62
63
  coverband.instance_variable_set('@store', nil)
63
64
  assert_equal false, coverband.instance_variable_get('@enabled')
64
65
  logger.expects(:info).at_least_once
66
+ logger.stubs('debug')
65
67
  coverband.start
66
- logger.info(1 + 1)
67
68
  coverband.stop
68
69
  coverband.save
69
70
  end
@@ -74,6 +75,7 @@ class CollectorsBaseTest < Test::Unit::TestCase
74
75
  coverband.instance_variable_set('@sample_percentage', 100.0)
75
76
  coverband.instance_variable_set('@verbose', true)
76
77
  Coverband.configuration.logger.stubs('info')
78
+ Coverband.configuration.logger.stubs('debug')
77
79
  store = Coverband::Adapters::RedisStore.new(Redis.new)
78
80
  coverband.instance_variable_set('@store', store)
79
81
  store.expects(:save_report).once.with(has_entries(dog_file => {5 => 5}))
@@ -61,7 +61,8 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
61
61
  coverband.instance_variable_set('@logger', logger)
62
62
  coverband.instance_variable_set('@store', nil)
63
63
  assert_equal false, coverband.instance_variable_get('@enabled')
64
- logger.expects(:info).at_least_once
64
+ logger.stubs('info')
65
+ logger.expects(:debug).at_least_once
65
66
  coverband.sample { 1 + 1 }
66
67
  assert_equal true, coverband.instance_variable_get('@enabled')
67
68
  end
@@ -74,6 +75,7 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
74
75
  coverband.instance_variable_set('@store', nil)
75
76
  assert_equal false, coverband.instance_variable_get('@enabled')
76
77
  logger.expects(:info).at_least_once
78
+ logger.stubs('debug')
77
79
  coverband.start
78
80
  logger.info(1 + 1)
79
81
  coverband.stop
@@ -83,8 +85,6 @@ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0')
83
85
  test 'allow reporting to redis start stop save' do
84
86
  dog_file = File.expand_path('./dog.rb', File.dirname(__FILE__))
85
87
  coverband.instance_variable_set('@sample_percentage', 100.0)
86
- coverband.instance_variable_set('@verbose', true)
87
- Coverband.configuration.logger.stubs('info')
88
88
  store = Coverband::Adapters::RedisStore.new(Redis.new)
89
89
  coverband.instance_variable_set('@store', store)
90
90
 
@@ -50,6 +50,7 @@ class CollectorsTraceTest < Test::Unit::TestCase
50
50
  coverband.instance_variable_set('@store', nil)
51
51
  assert_equal false, coverband.instance_variable_get('@enabled')
52
52
  logger.expects(:info).at_least_once
53
+ logger.stubs('debug')
53
54
  coverband.sample { 1 + 1 }
54
55
  assert_equal true, coverband.instance_variable_get('@enabled')
55
56
  end
@@ -63,8 +64,8 @@ class CollectorsTraceTest < Test::Unit::TestCase
63
64
  coverband.instance_variable_set('@store', nil)
64
65
  assert_equal false, coverband.instance_variable_get('@enabled')
65
66
  logger.expects(:info).at_least_once
67
+ logger.stubs('debug')
66
68
  coverband.start
67
- logger.info(1 + 1)
68
69
  coverband.stop
69
70
  coverband.save
70
71
  end
@@ -75,6 +76,7 @@ class CollectorsTraceTest < Test::Unit::TestCase
75
76
  coverband.instance_variable_set('@sample_percentage', 100.0)
76
77
  coverband.instance_variable_set('@verbose', true)
77
78
  Coverband.configuration.logger.stubs('info')
79
+ Coverband.configuration.logger.stubs('debug')
78
80
  store = Coverband::Adapters::RedisStore.new(Redis.new)
79
81
  coverband.instance_variable_set('@store', store)
80
82
  store.expects(:save_report).once.with(has_entries(dog_file => { 5 => 5 }))
@@ -2,7 +2,7 @@
2
2
 
3
3
  require File.expand_path('../test_helper', File.dirname(__FILE__))
4
4
  require 'aws-sdk'
5
- require File.expand_path('../../lib/coverband/s3_web', File.dirname(__FILE__))
5
+ require File.expand_path('../../lib/coverband/reporters/web', File.dirname(__FILE__))
6
6
  require 'rack/test'
7
7
 
8
8
  ENV['RACK_ENV'] = 'test'
@@ -12,15 +12,22 @@ module Coverband
12
12
  include Rack::Test::Methods
13
13
 
14
14
  def app
15
- Coverband::S3Web
15
+ Coverband::Reporters::Web.new
16
16
  end
17
17
 
18
- test 'renders content from the coverband/index.html object' do
18
+ # TODO add tests for all endpoints
19
+ test 'renders index content' do
20
+ get '/'
21
+ assert last_response.ok?
22
+ assert_match 'Coverband Web Admin Index', last_response.body
23
+ end
24
+
25
+ test 'renders show content' do
19
26
  Coverband.configuration.s3_bucket = 'coverage-bucket'
20
27
  s3 = mock('s3')
21
28
  Aws::S3::Client.expects(:new).returns(s3)
22
29
  s3.expects(:get_object).with(bucket: 'coverage-bucket', key: 'coverband/index.html').returns mock('response', body: mock('body', read: 'content'))
23
- get '/'
30
+ get '/show'
24
31
  assert last_response.ok?
25
32
  assert_equal 'content', last_response.body
26
33
  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: 2.0.1
4
+ version: 2.0.2.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-08-08 00:00:00.000000000 Z
11
+ date: 2018-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -108,20 +108,6 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: sinatra
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: test-unit
127
113
  requirement: !ruby/object:Gem::Requirement
@@ -207,6 +193,7 @@ files:
207
193
  - README.md
208
194
  - Rakefile
209
195
  - changes.md
196
+ - config.ru
210
197
  - coverband.gemspec
211
198
  - docs/coverband-install-resize.gif
212
199
  - docs/coverband_details.png
@@ -217,7 +204,6 @@ files:
217
204
  - lib/coverband/adapters/file_store.rb
218
205
  - lib/coverband/adapters/memory_cache_store.rb
219
206
  - lib/coverband/adapters/redis_store.rb
220
- - lib/coverband/baseline.rb
221
207
  - lib/coverband/collectors/base.rb
222
208
  - lib/coverband/collectors/coverage.rb
223
209
  - lib/coverband/collectors/trace.rb
@@ -226,8 +212,8 @@ files:
226
212
  - lib/coverband/reporters/base.rb
227
213
  - lib/coverband/reporters/console_report.rb
228
214
  - lib/coverband/reporters/simple_cov_report.rb
215
+ - lib/coverband/reporters/web.rb
229
216
  - lib/coverband/s3_report_writer.rb
230
- - lib/coverband/s3_web.rb
231
217
  - lib/coverband/tasks.rb
232
218
  - lib/coverband/version.rb
233
219
  - test/benchmarks/.gitignore
@@ -238,7 +224,6 @@ files:
238
224
  - test/unit/adapters_file_store_test.rb
239
225
  - test/unit/adapters_memory_cache_store_test.rb
240
226
  - test/unit/adapters_redis_store_test.rb
241
- - test/unit/baseline_test.rb
242
227
  - test/unit/collectors_base_test.rb
243
228
  - test/unit/collectors_coverage_test.rb
244
229
  - test/unit/collectors_trace_test.rb
@@ -248,8 +233,8 @@ files:
248
233
  - test/unit/reports_base_test.rb
249
234
  - test/unit/reports_console_test.rb
250
235
  - test/unit/reports_simple_cov_test.rb
236
+ - test/unit/reports_web_test.rb
251
237
  - test/unit/s3_report_writer_test.rb
252
- - test/unit/s3_web_test.rb
253
238
  homepage: https://github.com/danmayer/coverband
254
239
  licenses:
255
240
  - MIT
@@ -265,9 +250,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
265
250
  version: '0'
266
251
  required_rubygems_version: !ruby/object:Gem::Requirement
267
252
  requirements:
268
- - - ">="
253
+ - - ">"
269
254
  - !ruby/object:Gem::Version
270
- version: '0'
255
+ version: 1.3.1
271
256
  requirements: []
272
257
  rubyforge_project:
273
258
  rubygems_version: 2.5.1
@@ -283,7 +268,6 @@ test_files:
283
268
  - test/unit/adapters_file_store_test.rb
284
269
  - test/unit/adapters_memory_cache_store_test.rb
285
270
  - test/unit/adapters_redis_store_test.rb
286
- - test/unit/baseline_test.rb
287
271
  - test/unit/collectors_base_test.rb
288
272
  - test/unit/collectors_coverage_test.rb
289
273
  - test/unit/collectors_trace_test.rb
@@ -293,5 +277,5 @@ test_files:
293
277
  - test/unit/reports_base_test.rb
294
278
  - test/unit/reports_console_test.rb
295
279
  - test/unit/reports_simple_cov_test.rb
280
+ - test/unit/reports_web_test.rb
296
281
  - test/unit/s3_report_writer_test.rb
297
- - test/unit/s3_web_test.rb
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coverband
4
- class Baseline
5
- def self.record
6
- require 'coverage'
7
- Coverage.start
8
- yield
9
-
10
- project_directory = File.expand_path(Coverband.configuration.root)
11
- results = Coverage.result
12
- results = results.reject { |key, _val| !key.match(project_directory) || Coverband.configuration.ignore.any? { |pattern| key.match(/#{pattern}/) } }
13
-
14
- Coverband.configuration.store.save_report(convert_coverage_format(results))
15
- end
16
-
17
- def self.parse_baseline(_back_compat = nil)
18
- Coverband.configuration.store.coverage
19
- end
20
-
21
- def self.exclude_files(files)
22
- Coverband.configuration.ignore.each do |ignore|
23
- path = Coverband.configuration.root + "/#{ignore}"
24
- excludes = File.directory?(path) ? Dir.glob("#{path}/**/*") : [path]
25
- files -= excludes
26
- end
27
- files
28
- end
29
-
30
- private
31
-
32
- def self.convert_coverage_format(results)
33
- file_map = {}
34
- results.each_pair do |file, data|
35
- lines_map = {}
36
- data.each_with_index do |hits, index|
37
- lines_map[(index + 1)] = hits unless hits.nil?
38
- end
39
- file_map[file] = lines_map
40
- end
41
- file_map
42
- end
43
- end
44
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sinatra/base'
4
-
5
- module Coverband
6
- class S3Web < Sinatra::Base
7
- set :public_folder, proc(){ File.expand_path('public', Gem::Specification.find_by_name('simplecov-html').full_gem_path) }
8
-
9
- get '/' do
10
- html = s3.get_object(bucket: Coverband.configuration.s3_bucket, key: 'coverband/index.html').body.read
11
- # hack the static HTML assets to account for where this was mounted
12
- html = html.gsub("src='", "src='#{request.path}")
13
- html = html.gsub("href='", "href='#{request.path}")
14
- html = html.gsub("loading.gif", "#{request.path}loading.gif")
15
- html = html.gsub("/images/", "#{request.path}/images/")
16
- html
17
- end
18
-
19
- post '/update_report' do
20
- Coverband::Reporters::SimpleCovReport.report(Coverband.configuration.store, open_report: false)
21
- notice = "coverband coverage updated"
22
- redirect "/?notice=#{notice}", 301
23
- end
24
-
25
- post '/clear' do
26
- Coverband.configuration.store.clear!
27
- notice = "coverband coverage cleared"
28
- redirect "/?notice=#{notice}", 301
29
- end
30
-
31
- post '/reload_files' do
32
- if Coverband.configuration.safe_reload_files
33
- Coverband.configuration.safe_reload_files.each do |safe_file|
34
- load safe_file
35
- end
36
- end
37
- Coverband.configure
38
- notice = "coverband files reloaded"
39
- redirect "/?notice=#{notice}", 301
40
- end
41
-
42
- private
43
-
44
- def s3
45
- begin
46
- require 'aws-sdk'
47
- rescue StandardError
48
- Coverband.configuration.logger.error "coverband requires 'aws-sdk' in order use S3ReportWriter."
49
- return
50
- end
51
- @s3 ||= begin
52
- client_options = {
53
- region: Coverband.configuration.s3_region,
54
- access_key_id: Coverband.configuration.s3_access_key_id,
55
- secret_access_key: Coverband.configuration.s3_secret_access_key
56
- }
57
- client_options = {} if client_options.values.any?(&:nil?)
58
- Aws::S3::Client.new(client_options)
59
- end
60
- end
61
- end
62
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require File.expand_path('../test_helper', File.dirname(__FILE__))
4
-
5
- class ReporterTest < Test::Unit::TestCase
6
-
7
- test 'record baseline' do
8
- Coverband.configure do |config|
9
- config.store = Coverband::Adapters::FileStore.new(TEST_COVERAGE_FILE)
10
- end
11
- Coverage.expects(:start).returns(true).at_least_once
12
- Coverage.expects(:result).returns('fake' => [0, 1]).at_least_once
13
- File.expects(:open).once
14
-
15
- File.expects(:exist?).at_least_once.returns(true)
16
- expected = { 'filename.rb' => [0, nil, 1] }
17
- fake_file_data = expected.to_json
18
- File.expects(:read).at_least_once.returns(fake_file_data)
19
-
20
- Coverband::Baseline.record do
21
- # nothing
22
- end
23
- end
24
-
25
- test 'parse baseline' do
26
- Coverband.configure do |config|
27
- config.redis = nil
28
- config.store = nil
29
- config.root = '/full/remote_app/path'
30
- config.store = Coverband::Adapters::FileStore.new(TEST_COVERAGE_FILE)
31
- end
32
- File.expects(:exist?).at_least_once.returns(true)
33
- expected = { 'filename.rb' => [0, nil, 1] }
34
- fake_file_data = expected.to_json
35
- File.expects(:read).at_least_once.returns(fake_file_data)
36
- results = Coverband::Baseline.parse_baseline
37
- assert_equal(results, 'filename.rb' => [0, nil, 1])
38
- end
39
-
40
- test 'exclude_files' do
41
- Coverband.configure do |config|
42
- config.redis = nil
43
- config.store = nil
44
- config.root = '/full/remote_app/path'
45
- config.store = Coverband::Adapters::FileStore.new(TEST_COVERAGE_FILE)
46
- config.ignore = ['ignored_file.rb']
47
- end
48
- root = Coverband.configuration.root
49
- files = [root + '/ignored_file.rb', root + '/fakefile.rb']
50
- expected_files = [root + '/fakefile.rb']
51
- assert_equal(expected_files, Coverband::Baseline.exclude_files(files))
52
- end
53
-
54
- test 'convert_coverage_format' do
55
- results = { 'fake_file.rb' => [1, nil, 0, 2] }
56
- expected = { 'fake_file.rb' => { 1 => 1, 3 => 0, 4 => 2 } }
57
- assert_equal(expected, Coverband::Baseline.convert_coverage_format(results))
58
- end
59
- end