Skip to content

Instantly share code, notes, and snippets.

@jch
Created February 5, 2016 21:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jch/43b239cf480506696904 to your computer and use it in GitHub Desktop.
Save jch/43b239cf480506696904 to your computer and use it in GitHub Desktop.
require 'rack'
# Track changes in rack requests and responses made by middleware.
#
# SomeMiddleware
# request: ...
# response: ...
# AnotherMiddleware
# request: ...
# response: ...
# Endpoint
# request: ...
# response: ...
#
# Endpoints are not aware of the middlewares above them. Sinatra has
# middlewares, but then we miss the general ones from config.ru
module Rack::Tracer
def self.included(base)
trace = Trace.new
base.instance_variable_set :@_rack_trace, trace
end
def call(env)
response = super
response.define_singleton_method(:rack_trace) do
@_rack_trace
end
response
end
class Trace
def initialize(middlewares=[])
@middlewares = middlewares
@chain = []
end
end
end
class SomeMiddleware
def initialize(app)
@app = app
end
def call(env)
env['X-From'] = 'SomeMiddleware'
@app.call(env)
end
end
class SomeEndpoint
include Rack::Tracer
def call(env)
[200, {'X-From' => 'SomeEndpoint'}, ["SomeEndpoint body"]]
end
end
require 'minitest/autorun'
require 'rack/test'
class RackTracerTest < Minitest::Test
include Rack::Test::Methods
def app
Rack::Builder.app do
use SomeMiddleware
run SomeEndpoint.new
end
end
# Look into TracePoint API http://ruby-doc.org/core-2.0.0/TracePoint.html to
# record calls to `call` method. Not good enough because we can't record what
# was sent in / returned
def test_tracepoint_on_call_methods
trace = TracePoint.new(:call) do |tp|
if [SomeMiddleware, SomeEndpoint].include?(tp.defined_class)
p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
end
end
trace.enable
get "/"
trace.disable
end
def xtest_traces
get "/"
trace = last_response.rack_trace
assert_kind_of Rack::Tracer::Trace, trace
assert_same_elements [SomeMiddleware, SomeEndpoint], trace.chain.map(&:middleware)
end
def xtest_trace_chain_inspect
get "/"
trace = last_response.rack_trace
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment