require 'spec_helper' require 'rack-mini-profiler' require 'rack/test' describe Rack::MiniProfiler do include Rack::Test::Methods def app @app ||= Rack::Builder.new { use Rack::MiniProfiler map '/path2/a' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, '

path1

'] } end map '/path1/a' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, '

path2

'] } end map '/post' do run lambda { |env| [302, {'Content-Type' => 'text/html'}, '

POST

'] } end map '/html' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, "

Hi

\n \t"] } end map '/implicitbody' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, "

Hi

"] } end map '/implicitbodyhtml' do run lambda { |env| [200, {'Content-Type' => 'text/html'}, "

Hi

"] } end map '/db' do run lambda { |env| ::Rack::MiniProfiler.record_sql("I want to be, in a db", 10) [200, {'Content-Type' => 'text/html'}, '

Hi+db

'] } end map '/3ms' do run lambda { |env| sleep(0.003) [200, {'Content-Type' => 'text/html'}, '

Hi

'] } end map '/whitelisted' do run lambda { |env| Rack::MiniProfiler.authorize_request [200, {'Content-Type' => 'text/html'}, '

path1

'] } end }.to_app end before do Rack::MiniProfiler.reset_config end describe 'with a valid request' do before do get '/html' end it 'returns 200' do last_response.should be_ok end it 'has the X-MiniProfiler-Ids header' do last_response.headers.has_key?('X-MiniProfiler-Ids').should be_true end it 'has only one X-MiniProfiler-Ids header' do h = last_response.headers['X-MiniProfiler-Ids'] ids = ::JSON.parse(h) ids.count.should == 1 end it 'has the JS in the body' do last_response.body.include?('/mini-profiler-resources/includes.js').should be_true end it 'has a functioning share link' do h = last_response.headers['X-MiniProfiler-Ids'] id = ::JSON.parse(h)[0] get "/mini-profiler-resources/results?id=#{id}" last_response.should be_ok end it 'avoids xss attacks' do h = last_response.headers['X-MiniProfiler-Ids'] id = ::JSON.parse(h)[0] get "/mini-profiler-resources/results?id=%22%3E%3Cqss%3E" last_response.should_not be_ok last_response.body.should_not =~ // last_response.body.should =~ /<qss>/ end end describe 'with an implicit body tag' do before do get '/implicitbody' end it 'has the JS in the body' do last_response.body.include?('/mini-profiler-resources/includes.js').should be_true end end describe 'with implicit body and html tags' do before do get '/implicitbodyhtml' end it 'does not include the JS in the body' do last_response.body.include?('/mini-profiler-resources/includes.js').should be_false end end describe 'with a SCRIPT_NAME' do before do get '/html', nil, 'SCRIPT_NAME' => '/test' end it 'has the JS in the body with the correct path' do last_response.body.include?('/test/mini-profiler-resources/includes.js').should be_true end end describe 'configuration' do it "doesn't add MiniProfiler if the callback fails" do Rack::MiniProfiler.config.pre_authorize_cb = lambda {|env| false } get '/html' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_false end it "skips paths listed" do Rack::MiniProfiler.config.skip_paths = ['/path/', '/path2/'] get '/path2/a' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_false get '/path1/a' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_true end it 'disables default functionality' do Rack::MiniProfiler.config.enabled = false get '/html' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_false end end def load_prof(response) id = response.headers['X-MiniProfiler-Ids'] id = ::JSON.parse(id)[0] Rack::MiniProfiler.config.storage_instance.load(id) end describe 'special options' do it "omits db backtrace if requested" do get '/db?pp=no-backtrace' prof = load_prof(last_response) stack = prof["Root"]["SqlTimings"][0]["StackTraceSnippet"] stack.should be_nil end it 'disables functionality if requested' do get '/html?pp=disable' last_response.body.should_not include('/mini-profiler-resources/includes.js') end context 'when disabled' do before(:each) do get '/html?pp=disable' get '/html' last_response.body.should_not include('/mini-profiler-resources/includes.js') end it 're-enables functionality if requested' do get '/html?pp=enable' last_response.body.should include('/mini-profiler-resources/includes.js') end it "does not re-enable functionality if not whitelisted" do Rack::MiniProfiler.config.authorization_mode = :whitelist get '/html?pp=enable' last_response.body.should_not include('/mini-profiler-resources/includes.js') end it "re-enabled functionality if whitelisted" do Rack::MiniProfiler.config.authorization_mode = :whitelist expect(Rack::MiniProfiler).to receive(:request_authorized?) { true }.twice get '/html?pp=enable' last_response.body.should include('/mini-profiler-resources/includes.js') end end end describe 'POST followed by GET' do it "should end up with 2 ids" do post '/post' get '/html' ids = last_response.headers['X-MiniProfiler-Ids'] ::JSON.parse(ids).length.should == 2 end end describe 'authorization mode whitelist' do before do Rack::MiniProfiler.config.authorization_mode = :whitelist end it "should ban requests that are not whitelisted" do get '/html' last_response.headers['X-MiniProfiler-Ids'].should be_nil end it "should allow requests that are whitelisted" do set_cookie("__profilin=stylin") get '/whitelisted' last_response.headers['X-MiniProfiler-Ids'].should_not be_nil end end describe 'gc profiler' do it "should return a report" do get '/html?pp=profile-gc' last_response.header['Content-Type'].should == 'text/plain' end end describe 'error handling when storage_instance fails to save' do it "should recover gracefully" do Rack::MiniProfiler.config.pre_authorize_cb = lambda {|env| true } Rack::MiniProfiler::MemoryStore.any_instance.stub(:save) { raise "This error" } Rack::MiniProfiler.config.storage_failure.should_receive(:call) get '/html' end end describe 'when profiler is disabled by default' do before(:each) do Rack::MiniProfiler.config.enabled = false get '/html' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_false end it 'functionality can be re-enabled' do get '/html?pp=enable' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_true get '/html' last_response.headers.has_key?('X-MiniProfiler-Ids').should be_true end end end