Skip to content

Commit

Permalink
add support for route count
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Mayer committed Oct 1, 2022
1 parent b36d9c8 commit c136cb1
Show file tree
Hide file tree
Showing 16 changed files with 325 additions and 17 deletions.
1 change: 1 addition & 0 deletions lib/coverband.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
require "coverband/collectors/coverage"
require "coverband/collectors/view_tracker"
require "coverband/collectors/view_tracker_service"
require "coverband/collectors/route_tracker"
require "coverband/reporters/base"
require "coverband/reporters/console_report"
require "coverband/integrations/background"
Expand Down
35 changes: 31 additions & 4 deletions lib/coverband/collectors/route_tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,20 @@ def initialize(options = {})
@ignore_patterns = Coverband.configuration.ignore
@store = options.fetch(:store) { Coverband.configuration.store }
@logger = options.fetch(:logger) { Coverband.configuration.logger }
@target = options.fetch(:target) { [Rails.routes] }
@target = options.fetch(:target) do
if defined?(Rails.application)
Rails.application.routes.routes.map do |route|
{
controller: route.defaults[:controller],
action: route.defaults[:action],
url_path: route.path.spec.to_s.gsub("(.:format)", ""),
verb: route.verb
}.to_s
end
else
[]
end
end

@one_time_timestamp = false

Expand All @@ -40,7 +53,22 @@ def routes_to_record
# and ensure high performance
###
def track_routes(_name, _start, _finish, _id, payload)
if (route = payload[:identifier])
route = if payload[:request]
{
controller: nil,
action: nil,
url_path: payload[:request].path,
verb: payload[:request].method
}
else
{
controller: payload[:controller],
action: payload[:action],
url_path: payload[:path],
verb: payload[:method]
}
end
if route
if newly_seen_route?(route)
@logged_routes << route
@routes_to_record << route if track_route?(route)
Expand All @@ -52,7 +80,6 @@ def used_routes
redis_store.hgetall(tracker_key)
end

# TODO: likely not needed
def all_routes
all_routes = []
target.each do |route|
Expand Down Expand Up @@ -119,7 +146,7 @@ def newly_seen_route?(route)
end

def track_route?(route, options = {})
@ignore_patterns.none? { |pattern| route.include?(pattern) }
@ignore_patterns.none? { |pattern| route.to_s.include?(pattern) }
end

private
Expand Down
1 change: 1 addition & 0 deletions lib/coverband/integrations/background.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def self.start
sleep(sleep_seconds.to_i) if Coverband.configuration.defer_eager_loading_data?
Coverband.report_coverage
Coverband.configuration.view_tracker&.report_views_tracked
Coverband.configuration.route_tracker&.report_routes_tracked
if Coverband.configuration.verbose
logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
end
Expand Down
45 changes: 41 additions & 4 deletions lib/coverband/reporters/web.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ def call(env)
request_path_info = request.path_info == "" ? "/" : request.path_info
if request.post?
case request_path_info
when %r{\/clear_route_tracking_route}
clear_route_tracking_route
when %r{\/clear_route_tracking}
clear_route_tracking
when %r{\/clear_view_tracking_file}
clear_view_tracking_file
when %r{\/clear_view_tracking}
Expand All @@ -59,6 +63,8 @@ def call(env)
[200, {"Content-Type" => "text/json"}, [view_tracker_data]]
when %r{\/view_tracker}
[200, {"Content-Type" => "text/html"}, [view_tracker]]
when %r{\/route_tracker}
[200, {"Content-Type" => "text/html"}, [route_tracker]]
when %r{\/enriched_debug_data}
[200, {"Content-Type" => "text/json"}, [enriched_debug_data]]
when %r{\/debug_data}
Expand Down Expand Up @@ -95,6 +101,14 @@ def view_tracker
base_path: base_path).format_view_tracker!
end

def route_tracker
notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params["notice"])}<br/>"
notice = request.params["notice"] ? notice : ""
Coverband::Utils::HTMLFormatter.new(nil,
notice: notice,
base_path: base_path).format_route_tracker!
end

def view_tracker_data
Coverband::Collectors::ViewTracker.new(store: Coverband.configuration.store).as_json
end
Expand Down Expand Up @@ -126,7 +140,7 @@ def clear
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
[302, {"Location" => "#{base_path}?notice=#{notice}"}, []]
end

def clear_file
Expand All @@ -137,7 +151,7 @@ def clear_file
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[301, {"Location" => "#{base_path}?notice=#{notice}"}, []]
[302, {"Location" => "#{base_path}?notice=#{notice}"}, []]
end

def clear_view_tracking
Expand All @@ -148,7 +162,7 @@ def clear_view_tracking
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
[302, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
end

def clear_view_tracking_file
Expand All @@ -160,7 +174,30 @@ def clear_view_tracking_file
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[301, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
[302, {"Location" => "#{base_path}/view_tracker?notice=#{notice}"}, []]
end

def clear_route_tracking
if Coverband.configuration.web_enable_clear
tracker = Coverband::Collectors::RouteTracker.new(store: Coverband.configuration.store)
tracker.reset_recordings
notice = "route tracking reset"
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[302, {"Location" => "#{base_path}/route_tracker?notice=#{notice}"}, []]
end

def clear_route_tracking_route
if Coverband.configuration.web_enable_clear
tracker = Coverband::Collectors::RouteTracker.new(store: Coverband.configuration.store)
route = request.params["route"]
tracker.clear_route!(route)
notice = "coverage for route #{route} cleared"
else
notice = "web_enable_clear isn't enabled in your configuration"
end
[302, {"Location" => "#{base_path}/route_tracker?notice=#{notice}"}, []]
end

private
Expand Down
8 changes: 8 additions & 0 deletions lib/coverband/utils/html_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def format_view_tracker!
format_view_tracker
end

def format_route_tracker!
format_route_tracker
end

def format_source_file!(filename)
source_file = @coverage_result.file_from_path_with_type(filename)

Expand All @@ -57,6 +61,10 @@ def format_view_tracker
template("view_tracker").result(binding)
end

def format_route_tracker
template("route_tracker").result(binding)
end

def format(result)
Dir[File.join(File.dirname(__FILE__), "../../../public/*")].each do |path|
FileUtils.cp_r(path, asset_output_path)
Expand Down
9 changes: 8 additions & 1 deletion lib/coverband/utils/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ class Railtie < Rails::Railtie
Coverband.configuration.route_tracker = Coverband::Collectors::RouteTracker.new

ActiveSupport::Notifications.subscribe("start_processing.action_controller") do |name, start, finish, id, payload|
puts "name, start, finish, id, payload #{name}, start, finish, #{id}, #{payload}"
Coverband.configuration.route_tracker.track_routes(name, start, finish, id, payload)
end

# NOTE: This event was instrumented in Aug 10th 2022, but didn't make the 7.0.4 release and should be in the next release
# https://github.com/rails/rails/pull/43755
# Automatic tracking of redirects isn't avaible before Rails 7.1.0 (currently tested against the 7.1.0.alpha)
# We could consider back porting or patching a solution that works on previous Rails versions
ActiveSupport::Notifications.subscribe("redirect.action_dispatch") do |name, start, finish, id, payload|
Coverband.configuration.route_tracker.track_routes(name, start, finish, id, payload)
end
end
Expand Down
124 changes: 124 additions & 0 deletions test/coverband/collectors/route_tracker_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# frozen_string_literal: true

require File.expand_path("../../test_helper", File.dirname(__FILE__))
require "ostruct"

class RouterTrackerTest < Minitest::Test
def tracker_key
Coverband::Collectors::RouteTracker.expects(:supported_version?).at_least_once.returns(true)
Coverband::Collectors::RouteTracker.new.send(:tracker_key)
end

def setup
super
fake_store.raw_store.del(tracker_key)
end

test "init correctly" do
Coverband::Collectors::RouteTracker.expects(:supported_version?).returns(true)
tracker = Coverband::Collectors::RouteTracker.new(store: fake_store, roots: "dir")
assert_equal nil, tracker.target.first
assert !tracker.store.nil?
assert_equal [], tracker.target
assert_equal [], tracker.logged_routes
end

test "track redirect routes" do
store = fake_store
route_hash = {controller: nil, action: nil, url_path: "path", verb: "GET"}
store.raw_store.expects(:hset).with(tracker_key, route_hash, anything)
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
payload = {
request: OpenStruct.new(
path: "path",
method: "GET"
)
}
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.report_routes_tracked
assert_equal [route_hash], tracker.logged_routes
end

test "track controller routes" do
store = fake_store
route_hash = {controller: "SomeController", action: "index", url_path: "path", verb: "GET"}
store.raw_store.expects(:hset).with(tracker_key, route_hash, anything)
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
payload = {
controller: "SomeController",
action: "index",
path: "path",
method: "GET"
}
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.report_routes_tracked
assert_equal [route_hash], tracker.logged_routes
end

test "report used routes" do
store = fake_store
route_hash = {controller: "SomeController", action: "index", url_path: "path", verb: "GET"}
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
payload = {
controller: "SomeController",
action: "index",
path: "path",
method: "GET"
}
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.report_routes_tracked
assert_equal [route_hash.to_s], tracker.used_routes.keys
end

test "report unused routes" do
store = fake_store
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
payload = {
controller: "SomeController",
action: "index",
path: "path",
method: "GET"
}
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.report_routes_tracked
assert_equal [], tracker.unused_routes
end

test "reset store" do
store = fake_store
payload = {
controller: "SomeController",
action: "index",
path: "path",
method: "GET"
}
store.raw_store.expects(:del).with(tracker_key)
store.raw_store.expects(:del).with("route_tracker_time")
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.reset_recordings
end

test "clear_file" do
store = fake_store
route_hash = {controller: "SomeController", action: "index", url_path: "path", verb: "GET"}
tracker = Coverband::Collectors::RouteTracker.new(store: store, roots: "dir")
payload = {
controller: "SomeController",
action: "index",
path: "path",
method: "GET"
}
tracker.track_routes("name", "start", "finish", "id", payload)
tracker.report_routes_tracked
assert_equal [route_hash.to_s], tracker.used_routes.keys
tracker.clear_route!(route_hash.to_s)
assert_equal [], tracker.store.raw_store.hgetall(tracker_key).keys
end

protected

def fake_store
@fake_store ||= Coverband::Adapters::RedisStore.new(Coverband::Test.redis, redis_namespace: "coverband_test")
end
end
2 changes: 1 addition & 1 deletion test/coverband/collectors/view_tracker_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require File.expand_path("../../test_helper", File.dirname(__FILE__))

class ReporterTest < Minitest::Test
class ViewTrackerTest < Minitest::Test
def tracker_key
"render_tracker_2"
end
Expand Down
2 changes: 1 addition & 1 deletion test/coverband/reporters/web_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def teardown

test "clears coverband" do
post "/clear"
assert_equal 301, last_response.status
assert_equal 302, last_response.status
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions test/forked/rails_full_stack_views_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ def teardown
assert_content("I am no dummy view tracker text")
Coverband.report_coverage
Coverband.configuration.view_tracker&.report_views_tracked
Coverband.configuration.route_tracker&.report_routes_tracked
visit "/coverage/view_tracker"
assert_content("Used Views: (1)")
assert_content("Unused Views: (2)")
assert_selector("li.used-views", text: "dummy_view/show.html.erb")
assert_selector("li.unused-views", text: "dummy_view/show_haml.html.haml")
assert_selector("li.unused-views", text: "dummy_view/show_slim.html.slim")

visit "/coverage/route_tracker"
assert_content("Used Routes: (1)")
assert_content("Unused Routes: (5)")

visit "/dummy_view/show_haml"
assert_content("I am haml text")
Coverband.report_coverage
Expand Down
Loading

0 comments on commit c136cb1

Please sign in to comment.