diff --git a/coverband.gemspec b/coverband.gemspec index 830f8897..35d07f94 100644 --- a/coverband.gemspec +++ b/coverband.gemspec @@ -28,11 +28,13 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'test-unit' spec.add_development_dependency 'redis' spec.add_development_dependency 'benchmark-ips' + spec.add_development_dependency 'm' + # used for benchmarking and tests spec.add_development_dependency 'classifier-reborn' # add when debugging # require 'byebug'; byebug - spec.add_development_dependency 'byebug' + spec.add_development_dependency 'pry-byebug' # todo make an optional dependency for simplecov reports # also likely should just require simplecov-html not the whole lib diff --git a/lib/coverband.rb b/lib/coverband.rb index cf24cc4b..40f19d46 100644 --- a/lib/coverband.rb +++ b/lib/coverband.rb @@ -13,6 +13,8 @@ require 'coverband/reporters/base' require 'coverband/reporters/simple_cov_report' require 'coverband/reporters/console_report' +require 'coverband/integrations/background' +require 'coverband/integrations/rack_server_check' require 'coverband/reporters/web' require 'coverband/integrations/middleware' require 'coverband/integrations/background' @@ -44,5 +46,6 @@ def self.configuration def self.start Coverband::Collectors::Coverage.instance + Background.start if configuration.background_reporting_enabled && !RackServerCheck.running? end end diff --git a/lib/coverband/collectors/coverage.rb b/lib/coverband/collectors/coverage.rb index 6d0ecb53..00b0b73e 100644 --- a/lib/coverband/collectors/coverage.rb +++ b/lib/coverband/collectors/coverage.rb @@ -24,12 +24,15 @@ def reset_instance @verbose = Coverband.configuration.verbose @logger = Coverband.configuration.logger @current_thread = Thread.current + @background_reporting_enabled = Coverband.configuration.background_reporting_enabled Thread.current[:coverband_instance] = nil self end def report_coverage(force_report = false) + return Background.start if @background_reporting_enabled return if !ready_to_report? && !force_report + unless @store @logger.debug 'no store set, no-op' return diff --git a/lib/coverband/configuration.rb b/lib/coverband/configuration.rb index b2097daa..b425f01f 100644 --- a/lib/coverband/configuration.rb +++ b/lib/coverband/configuration.rb @@ -7,7 +7,8 @@ class Configuration :reporter, :reporting_frequency, :disable_on_failure_for, :redis_namespace, :redis_ttl, - :safe_reload_files + :safe_reload_files, :background_reporting_enabled, + :background_reporting_sleep_seconds attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id, :s3_secret_access_key @@ -29,6 +30,7 @@ def initialize @s3_secret_access_key = nil @redis_namespace = nil @redis_ttl = nil + @background_reporting_sleep_seconds = 30 end def logger diff --git a/lib/coverband/integrations/background.rb b/lib/coverband/integrations/background.rb index 0c3060a0..79375d8f 100644 --- a/lib/coverband/integrations/background.rb +++ b/lib/coverband/integrations/background.rb @@ -2,6 +2,25 @@ module Coverband class Background - # TODO: stub to implement background thread recording + @semaphore = Mutex.new + + def self.start + return if @background_reporting_running + + @semaphore.synchronize do + return if @background_reporting_running + + @background_reporting_running = true + sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds + logger = Coverband.configuration.logger + Thread.new do + loop do + Coverband::Collectors::Coverage.instance.report_coverage + logger&.debug("Reported coverage from thread. Sleeping for #{sleep_seconds} seconds") + sleep(sleep_seconds) + end + end + end + end end end diff --git a/lib/coverband/integrations/rack_server_check.rb b/lib/coverband/integrations/rack_server_check.rb new file mode 100644 index 00000000..c8d5069c --- /dev/null +++ b/lib/coverband/integrations/rack_server_check.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Coverband + class RackServerCheck + def self.running? + Kernel.caller_locations.any? { |line| line.path.include?('lib/rack/') } + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index dab723fa..2109cef1 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -7,6 +7,7 @@ require 'ostruct' require 'json' require 'redis' +require 'pry-byebug' SimpleCov.start do add_filter 'specs/ruby/1.9.1/gems/' diff --git a/test/unit/background_test.rb b/test/unit/background_test.rb new file mode 100644 index 00000000..8892c358 --- /dev/null +++ b/test/unit/background_test.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require File.expand_path('../test_helper', File.dirname(__FILE__)) + +class BackgroundTest < Test::Unit::TestCase + def test_start + Thread.expects(:new).yields + Coverband::Background.expects(:loop).yields + Coverband::Collectors::Coverage.instance.expects(:report_coverage) + Coverband::Background.expects(:sleep).with(30) + 2.times { Coverband::Background.start } + end +end + diff --git a/test/unit/collectors_coverage_test.rb b/test/unit/collectors_coverage_test.rb index feda5af5..4b7e3f4e 100644 --- a/test/unit/collectors_coverage_test.rb +++ b/test/unit/collectors_coverage_test.rb @@ -29,5 +29,12 @@ def teardown assert_equal Coverband::Adapters::RedisStore, coverband.instance_variable_get('@store').class end + test 'reports coverage in background when background reporting enabled' do + Coverband.configuration.stubs(:background_reporting_enabled).returns(true) + @coverband.reset_instance + Coverband::Background.expects(:start) + @coverband.report_coverage + end + end end diff --git a/test/unit/coverband_test.rb b/test/unit/coverband_test.rb new file mode 100644 index 00000000..a0522bea --- /dev/null +++ b/test/unit/coverband_test.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require File.expand_path('../test_helper', File.dirname(__FILE__)) + +class CoverbandTest < Test::Unit::TestCase + + test 'Coverband#start kicks off background reporting if enabled and not in rack server' do + Coverband.configuration.stubs(:background_reporting_enabled).returns(:true) + Coverband::RackServerCheck.expects(:running?).returns(false) + Coverband::Background.expects(:start) + Coverband.start + end + + test 'Coverband#start delays background reporting if enabled and running in a rack server' do + Coverband.configuration.stubs(:background_reporting_enabled).returns(true) + Coverband::RackServerCheck.expects(:running?).returns(true) + Coverband::Background.expects(:start).never + Coverband.start + end + + test 'Coverband#start does not kick off background reporting if not enabled' do + Coverband.configuration.stubs(:background_reporting_enabled).returns(false) + Coverband::Background.expects(:start).never + ::Coverband.start + end +end diff --git a/test/unit/rack_server_checkout_test.rb b/test/unit/rack_server_checkout_test.rb new file mode 100644 index 00000000..8b14523c --- /dev/null +++ b/test/unit/rack_server_checkout_test.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require File.expand_path('../test_helper', File.dirname(__FILE__)) + +class RackServerCheckTest < Test::Unit::TestCase + + test 'returns true when running in rack server' do + caller_locations = ['blah/lib/rack/server.rb'].map{ |path| OpenStruct.new(path: path) } + Kernel.expects(:caller_locations).returns(caller_locations) + assert_true(Coverband::RackServerCheck.running?) + end + + test 'returns false when not running in rack server' do + caller_locations = ['blah/lib/sidekiq/worker.rb'].map{ |path| OpenStruct.new(path: path) } + Kernel.expects(:caller_locations).returns(caller_locations) + assert_false(Coverband::RackServerCheck.running?) + end +end