wested-rack-bug 0.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +0 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.rdoc +29 -0
  5. data/Rakefile +20 -0
  6. data/Thorfile +109 -0
  7. data/VERSION +1 -0
  8. data/lib/rack/bug.rb +43 -0
  9. data/lib/rack/bug/options.rb +89 -0
  10. data/lib/rack/bug/panel.rb +50 -0
  11. data/lib/rack/bug/panel_app.rb +33 -0
  12. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  13. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  14. data/lib/rack/bug/panels/cache_panel.rb +50 -0
  15. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  16. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  17. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  18. data/lib/rack/bug/panels/log_panel.rb +39 -0
  19. data/lib/rack/bug/panels/log_panel/rails_extension.rb +11 -0
  20. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  21. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  22. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  23. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +14 -0
  24. data/lib/rack/bug/panels/redis_panel/stats.rb +48 -0
  25. data/lib/rack/bug/panels/request_variables_panel.rb +25 -0
  26. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  27. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  28. data/lib/rack/bug/panels/sql_panel/query.rb +73 -0
  29. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  30. data/lib/rack/bug/panels/templates_panel.rb +44 -0
  31. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  32. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  33. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  34. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  35. data/lib/rack/bug/params_signature.rb +65 -0
  36. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  37. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +215 -0
  38. data/lib/rack/bug/public/__rack_bug__/bug.css +211 -0
  39. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  40. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  41. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  42. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  43. data/lib/rack/bug/render.rb +66 -0
  44. data/lib/rack/bug/toolbar.rb +137 -0
  45. data/lib/rack/bug/views/error.html.erb +16 -0
  46. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  47. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  48. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  49. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  50. data/lib/rack/bug/views/panels/log.html.erb +23 -0
  51. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  52. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  53. data/lib/rack/bug/views/panels/redis.html.erb +32 -0
  54. data/lib/rack/bug/views/panels/request_variables.html.erb +107 -0
  55. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  56. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  57. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  58. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  59. data/lib/rack/bug/views/redirect.html.erb +16 -0
  60. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  61. data/spec/fixtures/config.ru +8 -0
  62. data/spec/fixtures/dummy_panel.rb +2 -0
  63. data/spec/fixtures/sample_app.rb +29 -0
  64. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  65. data/spec/rack/bug/panels/cache_panel_spec.rb +159 -0
  66. data/spec/rack/bug/panels/log_panel_spec.rb +25 -0
  67. data/spec/rack/bug/panels/memory_panel_spec.rb +21 -0
  68. data/spec/rack/bug/panels/rails_info_panel_spec.rb +25 -0
  69. data/spec/rack/bug/panels/redis_panel_spec.rb +57 -0
  70. data/spec/rack/bug/panels/sql_panel_spec.rb +136 -0
  71. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  72. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  73. data/spec/rack/toolbar_spec.rb +100 -0
  74. data/spec/rcov.opts +1 -0
  75. data/spec/spec.opts +1 -0
  76. data/spec/spec_helper.rb +70 -0
  77. data/wested-rack-bug.gemspec +127 -0
  78. metadata +153 -0
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe LogPanel do
5
+ before do
6
+ LogPanel.reset
7
+ header "rack-bug.panel_classes", [LogPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays 'Log'" do
12
+ response = get "/"
13
+ response.should have_heading("Log")
14
+ end
15
+ end
16
+
17
+ describe "content" do
18
+ it "displays recorded log lines" do
19
+ LogPanel.record("This is a logged message")
20
+ response = get "/"
21
+ response.should contain("This is a logged message")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe MemoryPanel do
5
+ before do
6
+ header "rack-bug.panel_classes", [MemoryPanel]
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays the total memory" do
11
+ response = get "/"
12
+ response.should have_heading(/\d+ KB total/)
13
+ end
14
+
15
+ it "displays the memory change during the request" do
16
+ response = get "/"
17
+ response.should have_heading(/\d+ KB Δ/)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe RailsInfoPanel do
5
+ before do
6
+ header "rack-bug.panel_classes", [RailsInfoPanel]
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays the Rails version" do
11
+ Rails.stub!(:version => "v2.3.0")
12
+ response = get "/"
13
+ response.should have_heading("Rails v2.3.0")
14
+ end
15
+ end
16
+
17
+ describe "content" do
18
+ it "displays the Rails::Info properties" do
19
+ Rails::Info.stub!(:properties => [["Name", "Value"]])
20
+ response = get "/"
21
+ response.should have_row("#rails_info", "Name", "Value")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ $LOADED_FEATURES << "redis.rb" #avoid dependency on redis
3
+
4
+ module Rack::Bug
5
+ describe RedisPanel do
6
+ before do
7
+ RedisPanel.reset
8
+ header "rack-bug.panel_classes", [RedisPanel]
9
+ end
10
+
11
+ describe "heading" do
12
+ it "displays the total redis time" do
13
+ response = get "/"
14
+ response.should have_heading("Redis: 0.00ms")
15
+ end
16
+ end
17
+
18
+ describe "content" do
19
+ describe "usage table" do
20
+ it "displays the total number of redis calls" do
21
+ RedisPanel.record(["get, user:1"]) { }
22
+ response = get "/"
23
+
24
+ # This causes a bus error:
25
+ # response.should have_selector("th:content('Total Calls') + td", :content => "1")
26
+
27
+ response.should have_row("#redis_usage", "Total Calls", "1")
28
+ end
29
+
30
+ it "displays the total redis time" do
31
+ response = get "/"
32
+ response.should have_row("#redis_usage", "Total Time", "0.00ms")
33
+ end
34
+ end
35
+
36
+ describe "breakdown" do
37
+ it "displays each redis operation" do
38
+ RedisPanel.record(["get, user:1"]) { }
39
+ response = get "/"
40
+ response.should have_row("#redis_breakdown", "get")
41
+ end
42
+
43
+ it "displays the time for redis call" do
44
+ RedisPanel.record(["get, user:1"]) { }
45
+ response = get "/"
46
+ response.should have_row("#redis_breakdown", "user:1", TIME_MS_REGEXP)
47
+ end
48
+
49
+ it "displays the arguments for each redis call" do
50
+ RedisPanel.record(["get, user:1"]) { }
51
+ response = get "/"
52
+ response.should have_row("#redis_breakdown", "user:1", "get")
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,136 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe SQLPanel do
5
+ before do
6
+ SQLPanel.reset
7
+ header "rack-bug.panel_classes", [SQLPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the total SQL query count" do
12
+ SQLPanel.record("SELECT NOW();") { }
13
+ response = get "/"
14
+ response.should have_heading("1 Queries")
15
+ end
16
+
17
+ it "displays the total SQL time" do
18
+ SQLPanel.record("SELECT NOW();") { }
19
+ response = get "/"
20
+ response.should have_heading(/Queries \(\d+\.\d{2}ms\)/)
21
+ end
22
+ end
23
+
24
+ describe "content" do
25
+ it "displays each executed SQL query" do
26
+ SQLPanel.record("SELECT NOW();") { }
27
+ response = get "/"
28
+ response.should have_row("#sql", "SELECT NOW();")
29
+ end
30
+
31
+ it "displays the time of each executed SQL query" do
32
+ SQLPanel.record("SELECT NOW();") { }
33
+ response = get "/"
34
+ response.should have_row("#sql", "SELECT NOW();", TIME_MS_REGEXP)
35
+ end
36
+ end
37
+
38
+ def stub_result(results = [[]])
39
+ columns = results.first
40
+ fields = columns.map { |c| stub("field", :name => c) }
41
+ rows = results[1..-1]
42
+
43
+ result = stub("result", :fetch_fields => fields)
44
+ result.stub!(:each).and_yield(*rows)
45
+ return result
46
+ end
47
+
48
+ def expect_query(sql, results)
49
+ conn = stub("connection")
50
+ ActiveRecord::Base.stub!(:connection => conn)
51
+ conn.should_receive(:execute).with(sql).and_return(stub_result(results))
52
+ end
53
+
54
+ describe "execute_sql" do
55
+ it "displays the query results" do
56
+ header "rack-bug.secret_key", "abc"
57
+ expect_query "SELECT username FROM users",
58
+ [["username"],
59
+ ["bryan"]]
60
+
61
+ response = get "/__rack_bug__/execute_sql", :query => "SELECT username FROM users",
62
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
63
+ response.should contain("SELECT username FROM users")
64
+ response.should be_ok
65
+ end
66
+
67
+ it "is forbidden when the hash is missing or wrong" do
68
+ header "rack-bug.secret_key", 'abc'
69
+
70
+ lambda {
71
+ get "/__rack_bug__/execute_sql", :query => "SELECT username FROM users",
72
+ :hash => "foobar"
73
+ }.should raise_error(SecurityError)
74
+ end
75
+
76
+ it "is not available when the rack-bug.secret_key is nil" do
77
+ header "rack-bug.secret_key", nil
78
+
79
+ lambda {
80
+ get "/__rack_bug__/execute_sql", :query => "SELECT username FROM users",
81
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
82
+ }.should raise_error(SecurityError)
83
+ end
84
+
85
+ it "is not available when the rack-bug.secret_key is an empty string" do
86
+ header "rack-bug.secret_key", ""
87
+
88
+ lambda {
89
+ get "/__rack_bug__/execute_sql", :query => "SELECT username FROM users",
90
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
91
+ }.should raise_error(SecurityError)
92
+ end
93
+ end
94
+
95
+ describe "explain_sql" do
96
+ it "displays the query explain plan" do
97
+ header "rack-bug.secret_key", "abc"
98
+ expect_query "EXPLAIN SELECT username FROM users",
99
+ [["table"],
100
+ ["users"]]
101
+
102
+ response = get "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
103
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
104
+ response.should contain("SELECT username FROM users")
105
+ response.should be_ok
106
+ end
107
+
108
+ it "is forbidden when the hash is missing or wrong" do
109
+ header "rack-bug.secret_key", 'abc'
110
+
111
+ lambda {
112
+ get "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
113
+ :hash => "foobar"
114
+ }.should raise_error(SecurityError)
115
+ end
116
+
117
+ it "is not available when the rack-bug.secret_key is nil" do
118
+ header "rack-bug.secret_key", nil
119
+
120
+ lambda {
121
+ get "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
122
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
123
+ }.should raise_error(SecurityError)
124
+ end
125
+
126
+ it "is not available when the rack-bug.secret_key is an empty string" do
127
+ header "rack-bug.secret_key", ""
128
+
129
+ lambda {
130
+ get "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
131
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
132
+ }.should raise_error(SecurityError)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe TemplatesPanel do
5
+ before do
6
+ TemplatesPanel.reset
7
+ header "rack-bug.panel_classes", [TemplatesPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the total rendering time" do
12
+ response = get "/"
13
+ response.should have_heading("Templates: 0.00ms")
14
+ end
15
+ end
16
+
17
+ describe "content" do
18
+ it "displays the template paths" do
19
+ TemplatesPanel.record("users/show") { }
20
+ response = get "/"
21
+ response.should contain("users/show")
22
+ end
23
+
24
+ it "displays the template children" do
25
+ TemplatesPanel.record("users/show") do
26
+ TemplatesPanel.record("users/toolbar") { }
27
+ end
28
+
29
+ response = get "/"
30
+ response.should have_selector("li", :content => "users/show") do |li|
31
+ li.should contain("users/toolbar")
32
+ end
33
+ end
34
+
35
+ context "for templates that rendered templates" do
36
+ it "displays the total time" do
37
+ TemplatesPanel.record("users/show") do
38
+ TemplatesPanel.record("users/toolbar") { }
39
+ end
40
+
41
+ response = get "/"
42
+ response.should have_selector("li", :content => "users/show") do |li|
43
+ li.should contain(TIME_MS_REGEXP)
44
+ end
45
+ end
46
+
47
+ it "displays the exclusive time" do
48
+ TemplatesPanel.record("users/show") do
49
+ TemplatesPanel.record("users/toolbar") { }
50
+ end
51
+
52
+ response = get "/"
53
+ response.should have_selector("li", :content => "users/show") do |li|
54
+ li.should contain(/\d\.\d{2} exclusive/)
55
+ end
56
+ end
57
+ end
58
+
59
+ context "for leaf templates" do
60
+ it "does not display the exclusive time" do
61
+ TemplatesPanel.record("users/show") { }
62
+
63
+ response = get "/"
64
+ response.should contain("users/show") do |li|
65
+ li.should_not contain("exclusive")
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,38 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ module Rack::Bug
4
+ describe TimerPanel do
5
+ before do
6
+ header "rack-bug.panel_classes", [TimerPanel]
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays the elapsed time" do
11
+ response = get "/"
12
+ response.should have_heading(TIME_MS_REGEXP)
13
+ end
14
+ end
15
+
16
+ describe "content" do
17
+ it "displays the user CPU time" do
18
+ response = get "/"
19
+ response.should have_row("#timer", "User CPU time", TIME_MS_REGEXP)
20
+ end
21
+
22
+ it "displays the system CPU time" do
23
+ response = get "/"
24
+ response.should have_row("#timer", "System CPU time", TIME_MS_REGEXP)
25
+ end
26
+
27
+ it "displays the total CPU time" do
28
+ response = get "/"
29
+ response.should have_row("#timer", "Total CPU time", TIME_MS_REGEXP)
30
+ end
31
+
32
+ it "displays the elapsed time" do
33
+ response = get "/"
34
+ response.should have_row("#timer", "Elapsed time", TIME_MS_REGEXP)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,100 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Rack::Bug do
4
+ it "inserts the Rack::Bug toolbar" do
5
+ response = get "/"
6
+ response.should have_selector("div#rack_bug")
7
+ end
8
+
9
+ it "updates the Content-Length" do
10
+ response = get "/"
11
+ response["Content-Length"].should == response.body.size.to_s
12
+ end
13
+
14
+ it "serves the Rack::Bug assets under /__rack_bug__/" do
15
+ response = get "/__rack_bug__/bug.css"
16
+ response.should be_ok
17
+ end
18
+
19
+ it "modifies HTML responses with a charset" do
20
+ response = get "/", :content_type => "application/xhtml+xml; charset=utf-8"
21
+ response.should have_selector("div#rack_bug")
22
+ end
23
+
24
+ it "does not modify XMLHttpRequest responses" do
25
+ response = get "/", {}, { :xhr => true }
26
+ response.should_not have_selector("div#rack_bug")
27
+ end
28
+
29
+ it "modifies XHTML responses" do
30
+ response = get "/", :content_type => "application/xhtml+xml"
31
+ response.should have_selector("div#rack_bug")
32
+ end
33
+
34
+ it "does not modify non-HTML responses" do
35
+ response = get "/", :content_type => "text/csv"
36
+ response.should_not have_selector("div#rack_bug")
37
+ end
38
+
39
+ it "does not modify redirects" do
40
+ response = get "/redirect"
41
+ response.body.should == ""
42
+ end
43
+
44
+ it "does not modify server errors" do
45
+ response = get "/error"
46
+ response.should_not have_selector("div#rack_bug")
47
+ end
48
+
49
+ context "configured to intercept redirects" do
50
+ it "inserts the Rack::Bug toolbar for redirects" do
51
+ response = get "/redirect", {}, "rack-bug.intercept_redirects" => true
52
+ response.should contain("Location: /")
53
+ end
54
+ end
55
+
56
+ context "configured with an IP address restriction" do
57
+ before do
58
+ header "rack-bug.ip_masks", [IPAddr.new("127.0.0.1/255.255.255.0")]
59
+ end
60
+
61
+ it "inserts the Rack::Bug toolbar when the IP matches" do
62
+ response = get "/", {}, "REMOTE_ADDR" => "127.0.0.2"
63
+ response.should have_selector("div#rack_bug")
64
+ end
65
+
66
+ it "is disabled when the IP doesn't match" do
67
+ response = get "/", {}, "REMOTE_ADDR" => "128.0.0.1"
68
+ response.should_not have_selector("div#rack_bug")
69
+ end
70
+
71
+ it "doesn't use any panels" do
72
+ DummyPanel.should_not_receive(:new)
73
+ header "rack-bug.panel_classes", [DummyPanel]
74
+ get "/", {}, "REMOTE_ADDR" => "128.0.0.1"
75
+ end
76
+ end
77
+
78
+ context "configured with a password" do
79
+ before do
80
+ header "rack-bug.password", "secret"
81
+ end
82
+
83
+ it "inserts the Rack::Bug toolbar when the password matches" do
84
+ sha = "545049d1c5e2a6e0dfefd37f9a9e0beb95241935"
85
+ response = get "/", {}, :cookie => ["rack_bug_enabled=1", "rack_bug_password=#{sha}"]
86
+ response.should have_selector("div#rack_bug")
87
+ end
88
+
89
+ it "is disabled when the password doesn't match" do
90
+ response = get "/"
91
+ response.should_not have_selector("div#rack_bug")
92
+ end
93
+
94
+ it "doesn't use any panels" do
95
+ DummyPanel.should_not_receive(:new)
96
+ header "rack-bug.panel_classes", [DummyPanel]
97
+ get "/"
98
+ end
99
+ end
100
+ end