ghazel-rack-bug 0.3.0.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 (86) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +45 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.md +118 -0
  5. data/Rakefile +23 -0
  6. data/Thorfile +113 -0
  7. data/lib/rack/bug.rb +83 -0
  8. data/lib/rack/bug/autoloading.rb +24 -0
  9. data/lib/rack/bug/filtered_backtrace.rb +38 -0
  10. data/lib/rack/bug/options.rb +89 -0
  11. data/lib/rack/bug/panel.rb +50 -0
  12. data/lib/rack/bug/panel_app.rb +33 -0
  13. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  14. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
  15. data/lib/rack/bug/panels/cache_panel.rb +51 -0
  16. data/lib/rack/bug/panels/cache_panel/dalli_extension.rb +16 -0
  17. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  18. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  19. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  20. data/lib/rack/bug/panels/log_panel.rb +56 -0
  21. data/lib/rack/bug/panels/log_panel/logger_extension.rb +24 -0
  22. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  23. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  24. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  25. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +28 -0
  26. data/lib/rack/bug/panels/redis_panel/stats.rb +52 -0
  27. data/lib/rack/bug/panels/request_variables_panel.rb +52 -0
  28. data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
  29. data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +25 -0
  30. data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
  31. data/lib/rack/bug/panels/sql_panel.rb +55 -0
  32. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  33. data/lib/rack/bug/panels/sql_panel/query.rb +63 -0
  34. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
  35. data/lib/rack/bug/panels/templates_panel.rb +44 -0
  36. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
  37. data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
  38. data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
  39. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  40. data/lib/rack/bug/params_signature.rb +63 -0
  41. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  42. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +217 -0
  43. data/lib/rack/bug/public/__rack_bug__/bug.css +216 -0
  44. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  45. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  46. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  47. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  48. data/lib/rack/bug/rack_static_bug_avoider.rb +16 -0
  49. data/lib/rack/bug/redirect_interceptor.rb +27 -0
  50. data/lib/rack/bug/render.rb +66 -0
  51. data/lib/rack/bug/toolbar.rb +66 -0
  52. data/lib/rack/bug/views/error.html.erb +16 -0
  53. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  54. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  55. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  56. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  57. data/lib/rack/bug/views/panels/log.html.erb +21 -0
  58. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  59. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  60. data/lib/rack/bug/views/panels/redis.html.erb +46 -0
  61. data/lib/rack/bug/views/panels/request_variables.html.erb +29 -0
  62. data/lib/rack/bug/views/panels/sphinx.html.erb +32 -0
  63. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  64. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  65. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  66. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  67. data/lib/rack/bug/views/redirect.html.erb +16 -0
  68. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  69. data/rack-bug.gemspec +147 -0
  70. data/spec/fixtures/config.ru +8 -0
  71. data/spec/fixtures/dummy_panel.rb +2 -0
  72. data/spec/fixtures/sample_app.rb +46 -0
  73. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  74. data/spec/rack/bug/panels/cache_panel_spec.rb +167 -0
  75. data/spec/rack/bug/panels/log_panel_spec.rb +43 -0
  76. data/spec/rack/bug/panels/memory_panel_spec.rb +22 -0
  77. data/spec/rack/bug/panels/rails_info_panel_spec.rb +40 -0
  78. data/spec/rack/bug/panels/redis_panel_spec.rb +69 -0
  79. data/spec/rack/bug/panels/sql_panel_spec.rb +146 -0
  80. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  81. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  82. data/spec/rack/bug_spec.rb +137 -0
  83. data/spec/rcov.opts +1 -0
  84. data/spec/spec.opts +1 -0
  85. data/spec/spec_helper.rb +44 -0
  86. metadata +201 -0
@@ -0,0 +1,30 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ class Rack::Bug
4
+ describe ActiveRecordPanel do
5
+ before do
6
+ ActiveRecordPanel.reset
7
+ rack_env "rack-bug.panel_classes", [ActiveRecordPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the total number of instantiated AR objects" do
12
+ ActiveRecordPanel.record("User")
13
+ ActiveRecordPanel.record("Group")
14
+ response = get_via_rack "/"
15
+ response.should have_heading("2 AR Objects")
16
+ end
17
+ end
18
+
19
+ describe "content" do
20
+ it "displays the count of instantiated objects for each class" do
21
+ ActiveRecordPanel.record("User")
22
+ ActiveRecordPanel.record("User")
23
+ ActiveRecordPanel.record("Group")
24
+ response = get_via_rack "/"
25
+ response.should have_row("#active_record", "User", "2")
26
+ response.should have_row("#active_record", "Group", "1")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,167 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ class Rack::Bug
4
+ describe CachePanel do
5
+ before do
6
+ CachePanel.reset
7
+ rack_env "rack-bug.panel_classes", [CachePanel]
8
+ unless defined?(Rails)
9
+ @added_rails = true
10
+ Object.const_set :Rails, Module.new
11
+ end
12
+ end
13
+
14
+ after do
15
+ Object.send :remove_const, :Rails if @added_rails
16
+ end
17
+
18
+ describe "heading" do
19
+ it "displays the total memcache time" do
20
+ response = get_via_rack "/"
21
+ response.should have_heading("Cache: 0.00ms")
22
+ end
23
+ end
24
+
25
+ describe "content" do
26
+ describe "usage table" do
27
+ it "displays the total number of memcache calls" do
28
+ CachePanel.record(:get, "user:1") { }
29
+ response = get_via_rack "/"
30
+
31
+ # This causes a bus error:
32
+ # response.should have_selector("th:content('Total Calls') + td", :content => "1")
33
+
34
+ response.should have_row("#cache_usage", "Total Calls", "1")
35
+ end
36
+
37
+ it "displays the total memcache time" do
38
+ response = get_via_rack "/"
39
+ response.should have_row("#cache_usage", "Total Time", "0.00ms")
40
+ end
41
+
42
+ it "dispays the number of memcache hits" do
43
+ CachePanel.record(:get, "user:1") { }
44
+ response = get_via_rack "/"
45
+ response.should have_row("#cache_usage", "Hits", "0")
46
+ end
47
+
48
+ it "displays the number of memcache misses" do
49
+ CachePanel.record(:get, "user:1") { }
50
+ response = get_via_rack "/"
51
+ response.should have_row("#cache_usage", "Misses", "1")
52
+ end
53
+
54
+ it "displays the number of memcache gets" do
55
+ CachePanel.record(:get, "user:1") { }
56
+ response = get_via_rack "/"
57
+ response.should have_row("#cache_usage", "gets", "1")
58
+ end
59
+
60
+ it "displays the number of memcache sets" do
61
+ CachePanel.record(:set, "user:1") { }
62
+ response = get_via_rack "/"
63
+ response.should have_row("#cache_usage", "sets", "1")
64
+ end
65
+
66
+ it "displays the number of memcache deletes" do
67
+ CachePanel.record(:delete, "user:1") { }
68
+ response = get_via_rack "/"
69
+ response.should have_row("#cache_usage", "deletes", "1")
70
+ end
71
+
72
+ it "displays the number of memcache get_multis" do
73
+ CachePanel.record(:get_multi, "user:1", "user:2") { }
74
+ response = get_via_rack "/"
75
+ response.should have_row("#cache_usage", "get_multis", "1")
76
+ end
77
+ end
78
+
79
+ describe "breakdown" do
80
+ it "displays each memcache operation" do
81
+ CachePanel.record(:get, "user:1") { }
82
+ response = get_via_rack "/"
83
+ response.should have_row("#cache_breakdown", "get")
84
+ end
85
+
86
+ it "displays the time for each memcache call" do
87
+ CachePanel.record(:get, "user:1") { }
88
+ response = get_via_rack "/"
89
+ response.should have_row("#cache_breakdown", "user:1", TIME_MS_REGEXP)
90
+ end
91
+
92
+ it "displays the keys for each memcache call" do
93
+ CachePanel.record(:get, "user:1") { }
94
+ response = get_via_rack "/"
95
+ response.should have_row("#cache_breakdown", "user:1", "get")
96
+ end
97
+ end
98
+ end
99
+
100
+ describe "expire_all" do
101
+ before do
102
+ rack_env "rack-bug.secret_key", 'abc'
103
+ end
104
+
105
+ it "expires the cache keys" do
106
+ Rails.stub!(:cache => mock("cache"))
107
+ Rails.cache.should_receive(:delete).with("user:1")
108
+ Rails.cache.should_receive(:delete).with("user:2")
109
+ Rails.cache.should_receive(:delete).with("user:3")
110
+ Rails.cache.should_receive(:delete).with("user:4")
111
+
112
+ get_via_rack "/__rack_bug__/delete_cache_list",
113
+ :keys_1 => "user:1", :keys_2 => "user:2", :keys_3 => "user:3", :keys_4 => "user:4",
114
+ :hash => "c367b76e0199c308862a3afd8fba32b8715e7976"
115
+ end
116
+
117
+ it "returns OK" do
118
+ Rails.stub!(:cache => mock("cache", :delete => nil))
119
+ response = get_via_rack "/__rack_bug__/delete_cache_list",
120
+ :keys_1 => "user:1", :keys_2 => "user:2", :keys_3 => "user:3", :keys_4 => "user:4",
121
+ :hash => "c367b76e0199c308862a3afd8fba32b8715e7976"
122
+ response.should contain("OK")
123
+ end
124
+ end
125
+
126
+ describe "expire" do
127
+ before do
128
+ rack_env "rack-bug.secret_key", 'abc'
129
+ end
130
+
131
+ it "expires the cache key" do
132
+ Rails.stub!(:cache => mock("cache"))
133
+ Rails.cache.should_receive(:delete).with("user:1")
134
+ get_via_rack "/__rack_bug__/delete_cache", :key => "user:1",
135
+ :hash => "f87215442d312d8e42cf51e6b66fc3eb3d59ac74"
136
+ end
137
+
138
+ it "returns OK" do
139
+ Rails.stub!(:cache => mock("cache", :delete => nil))
140
+ response = get_via_rack "/__rack_bug__/delete_cache", :key => "user:1",
141
+ :hash => "f87215442d312d8e42cf51e6b66fc3eb3d59ac74"
142
+ response.should contain("OK")
143
+ end
144
+ end
145
+
146
+ describe "view_cache" do
147
+ before do
148
+ rack_env "rack-bug.secret_key", 'abc'
149
+ end
150
+
151
+ it "renders the cache key" do
152
+ Rails.stub!(:cache => mock("cache", :read => "cache body"))
153
+ response = get_via_rack "/__rack_bug__/view_cache", :key => "user:1",
154
+ :hash => "f87215442d312d8e42cf51e6b66fc3eb3d59ac74"
155
+ response.should contain("cache body")
156
+ end
157
+
158
+ it "renders non-String cache values properly" do
159
+ Rails.stub!(:cache => mock("cache", :read => [1, 2]))
160
+ response = get_via_rack "/__rack_bug__/view_cache", :key => "user:1",
161
+ :hash => "f87215442d312d8e42cf51e6b66fc3eb3d59ac74"
162
+ response.should contain("[1, 2]")
163
+ end
164
+ end
165
+
166
+ end
167
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ class Rack::Bug
4
+ describe LogPanel do
5
+ before do
6
+ LogPanel.reset
7
+ rack_env "rack-bug.panel_classes", [LogPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays 'Log'" do
12
+ response = get_via_rack "/"
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", 0)
20
+ response = get_via_rack "/"
21
+ response.should contain("This is a logged message")
22
+ response.should contain("DEBUG")
23
+ end
24
+ end
25
+
26
+ describe "Extended Logger" do
27
+ it "does still return true/false for #add if class Logger" do
28
+ #AS::BufferedLogger returns the added string, Logger returns true/false
29
+ LOGGER.add(0, "foo").should == true
30
+ end
31
+ end
32
+
33
+
34
+ describe "With no logger defined" do
35
+ it "does not err out" do
36
+ logger = LOGGER
37
+ Object.send :remove_const, :LOGGER
38
+ lambda{ load("rack/bug/panels/log_panel/logger_extension.rb") }.should_not raise_error
39
+ ::LOGGER = logger
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
3
+
4
+ class Rack::Bug
5
+ describe MemoryPanel do
6
+ before do
7
+ rack_env "rack-bug.panel_classes", [MemoryPanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the total memory" do
12
+ response = get_via_rack "/"
13
+ response.should have_heading(/\d+ KB total/)
14
+ end
15
+
16
+ it "displays the memory change during the request" do
17
+ response = get_via_rack "/"
18
+ response.should have_heading(/\d+ KB Δ/)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ class Rack::Bug
4
+ describe RailsInfoPanel do
5
+ before do
6
+ rack_env "rack-bug.panel_classes", [RailsInfoPanel]
7
+
8
+ unless defined?(Rails)
9
+ @added_rails = true
10
+ Object.const_set :Rails, Module.new
11
+ Rails::Info = Class.new do
12
+ def self.properties
13
+ []
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ after do
20
+ Object.send :remove_const, :Rails if @added_rails
21
+ end
22
+
23
+ describe "heading" do
24
+ it "displays the Rails version" do
25
+ Rails.stub!(:version => "v2.3.0")
26
+ response = get_via_rack "/"
27
+ response.should have_heading("Rails v2.3.0")
28
+ end
29
+ end
30
+
31
+ describe "content" do
32
+ it "displays the Rails::Info properties" do
33
+ Rails.stub!(:version => "v2.3.0")
34
+ Rails::Info.stub!(:properties => [["Name", "Value"]])
35
+ response = get_via_rack "/"
36
+ response.should have_row("#rails_info", "Name", "Value")
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,69 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ $LOADED_FEATURES << "redis.rb" #avoid dependency on redis
3
+
4
+ class Rack::Bug
5
+ describe RedisPanel do
6
+ before do
7
+ RedisPanel.reset
8
+ rack_env "rack-bug.panel_classes", [RedisPanel]
9
+ end
10
+
11
+ describe "heading" do
12
+ it "displays the total redis time" do
13
+ response = get_via_rack "/"
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"], Kernel.caller) { }
22
+ response = get_via_rack "/"
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_via_rack "/"
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"], Kernel.caller) { }
39
+ response = get_via_rack "/"
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"], Kernel.caller) { }
45
+ response = get_via_rack "/"
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"], Kernel.caller) { }
51
+ response = get_via_rack "/"
52
+ response.should have_row("#redis_breakdown", "user:1", "get")
53
+ end
54
+
55
+ it "displays a link to show the backtrace when it's available" do
56
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
57
+ response = get_via_rack "/"
58
+ response.should have_row("#redis_breakdown", "user:1", "Show Backtrace")
59
+ end
60
+
61
+ it "does not display a link to show the backtrace when it's not available" do
62
+ RedisPanel.record(["get, user:1"], []) { }
63
+ response = get_via_rack "/"
64
+ response.should_not contain("Show Backtrace")
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,146 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ class Rack::Bug
4
+ describe SQLPanel do
5
+ before do
6
+ SQLPanel.reset
7
+ rack_env "rack-bug.panel_classes", [SQLPanel]
8
+
9
+ unless defined?(ActiveRecord)
10
+ @added_rails = true
11
+ Object.const_set :ActiveRecord, Module.new
12
+ ActiveRecord.const_set :Base, Class.new
13
+ end
14
+ end
15
+
16
+ after do
17
+ Object.send :remove_const, :ActiveRecord if @added_active_record
18
+ end
19
+
20
+ describe "heading" do
21
+ it "displays the total SQL query count" do
22
+ SQLPanel.record("SELECT NOW();") { }
23
+ response = get_via_rack "/"
24
+ response.should have_heading("1 Queries")
25
+ end
26
+
27
+ it "displays the total SQL time" do
28
+ SQLPanel.record("SELECT NOW();") { }
29
+ response = get_via_rack "/"
30
+ response.should have_heading(/Queries \(\d+\.\d{2}ms\)/)
31
+ end
32
+ end
33
+
34
+ describe "content" do
35
+ it "displays each executed SQL query" do
36
+ SQLPanel.record("SELECT NOW();") { }
37
+ response = get_via_rack "/"
38
+ response.should have_row("#sql", "SELECT NOW();")
39
+ end
40
+
41
+ it "displays the time of each executed SQL query" do
42
+ SQLPanel.record("SELECT NOW();") { }
43
+ response = get_via_rack "/"
44
+ response.should have_row("#sql", "SELECT NOW();", TIME_MS_REGEXP)
45
+ end
46
+ end
47
+
48
+ def stub_result(results = [[]])
49
+ columns = results.first
50
+ fields = columns.map { |c| stub("field", :name => c) }
51
+ rows = results[1..-1]
52
+
53
+ result = stub("result", :fetch_fields => fields)
54
+ result.stub!(:each).and_yield(*rows)
55
+ return result
56
+ end
57
+
58
+ def expect_query(sql, results)
59
+ conn = stub("connection")
60
+ ActiveRecord::Base.stub!(:connection => conn)
61
+ conn.should_receive(:execute).with(sql).and_return(stub_result(results))
62
+ end
63
+
64
+ describe "execute_sql" do
65
+ it "displays the query results" do
66
+ rack_env "rack-bug.secret_key", "abc"
67
+ expect_query "SELECT username FROM users",
68
+ [["username"],
69
+ ["bryan"]]
70
+
71
+ response = get_via_rack "/__rack_bug__/execute_sql", {:query => "SELECT username FROM users",
72
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"}, {:xhr => true}
73
+ response.should contain("SELECT username FROM users")
74
+ response.should be_ok
75
+ end
76
+
77
+ it "is forbidden when the hash is missing or wrong" do
78
+ rack_env "rack-bug.secret_key", 'abc'
79
+
80
+ lambda {
81
+ get_via_rack "/__rack_bug__/execute_sql", {:query => "SELECT username FROM users",
82
+ :hash => "foobar"}, {:xhr => true}
83
+ }.should raise_error(SecurityError)
84
+ end
85
+
86
+ it "is not available when the rack-bug.secret_key is nil" do
87
+ rack_env "rack-bug.secret_key", nil
88
+
89
+ lambda {
90
+ get_via_rack "/__rack_bug__/execute_sql", {:query => "SELECT username FROM users",
91
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"}, {:xhr => true}
92
+ }.should raise_error(SecurityError)
93
+ end
94
+
95
+ it "is not available when the rack-bug.secret_key is an empty string" do
96
+ rack_env "rack-bug.secret_key", ""
97
+
98
+ lambda {
99
+ get_via_rack "/__rack_bug__/execute_sql", {:query => "SELECT username FROM users",
100
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"}, {:xhr => true}
101
+ }.should raise_error(SecurityError)
102
+ end
103
+ end
104
+
105
+ describe "explain_sql" do
106
+ it "displays the query explain plan" do
107
+ rack_env "rack-bug.secret_key", "abc"
108
+ expect_query "EXPLAIN SELECT username FROM users",
109
+ [["table"],
110
+ ["users"]]
111
+
112
+ response = get_via_rack "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
113
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
114
+ response.should contain("SELECT username FROM users")
115
+ response.should be_ok
116
+ end
117
+
118
+ it "is forbidden when the hash is missing or wrong" do
119
+ rack_env "rack-bug.secret_key", 'abc'
120
+
121
+ lambda {
122
+ get_via_rack "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
123
+ :hash => "foobar"
124
+ }.should raise_error(SecurityError)
125
+ end
126
+
127
+ it "is not available when the rack-bug.secret_key is nil" do
128
+ rack_env "rack-bug.secret_key", nil
129
+
130
+ lambda {
131
+ get_via_rack "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
132
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
133
+ }.should raise_error(SecurityError)
134
+ end
135
+
136
+ it "is not available when the rack-bug.secret_key is an empty string" do
137
+ rack_env "rack-bug.secret_key", ""
138
+
139
+ lambda {
140
+ get_via_rack "/__rack_bug__/explain_sql", :query => "SELECT username FROM users",
141
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
142
+ }.should raise_error(SecurityError)
143
+ end
144
+ end
145
+ end
146
+ end