logical-insight 0.4.0

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 (100) hide show
  1. data/History.txt +45 -0
  2. data/MIT-LICENSE.txt +19 -0
  3. data/README.md +123 -0
  4. data/Rakefile +24 -0
  5. data/Thorfile +113 -0
  6. data/lib/insight.rb +17 -0
  7. data/lib/insight/app.rb +189 -0
  8. data/lib/insight/database.rb +186 -0
  9. data/lib/insight/enable-button.rb +43 -0
  10. data/lib/insight/filtered_backtrace.rb +45 -0
  11. data/lib/insight/instrumentation.rb +9 -0
  12. data/lib/insight/instrumentation/backstage.rb +10 -0
  13. data/lib/insight/instrumentation/client.rb +20 -0
  14. data/lib/insight/instrumentation/instrument.rb +109 -0
  15. data/lib/insight/instrumentation/package-definition.rb +58 -0
  16. data/lib/insight/instrumentation/probe-definition.rb +20 -0
  17. data/lib/insight/instrumentation/probe.rb +199 -0
  18. data/lib/insight/instrumentation/setup.rb +32 -0
  19. data/lib/insight/logger.rb +55 -0
  20. data/lib/insight/options.rb +102 -0
  21. data/lib/insight/panel.rb +119 -0
  22. data/lib/insight/panel_app.rb +31 -0
  23. data/lib/insight/panels-content.rb +22 -0
  24. data/lib/insight/panels-header.rb +18 -0
  25. data/lib/insight/panels/active_record_panel.rb +46 -0
  26. data/lib/insight/panels/cache_panel.rb +69 -0
  27. data/lib/insight/panels/cache_panel/panel_app.rb +46 -0
  28. data/lib/insight/panels/cache_panel/stats.rb +98 -0
  29. data/lib/insight/panels/log_panel.rb +54 -0
  30. data/lib/insight/panels/memory_panel.rb +32 -0
  31. data/lib/insight/panels/rails_info_panel.rb +19 -0
  32. data/lib/insight/panels/redis_panel.rb +42 -0
  33. data/lib/insight/panels/redis_panel/redis_extension.rb +23 -0
  34. data/lib/insight/panels/redis_panel/stats.rb +50 -0
  35. data/lib/insight/panels/request_variables_panel.rb +70 -0
  36. data/lib/insight/panels/speedtracer_panel.rb +89 -0
  37. data/lib/insight/panels/speedtracer_panel/trace-app.rb +52 -0
  38. data/lib/insight/panels/speedtracer_panel/tracer.rb +212 -0
  39. data/lib/insight/panels/sql_panel.rb +53 -0
  40. data/lib/insight/panels/sql_panel/panel_app.rb +37 -0
  41. data/lib/insight/panels/sql_panel/query.rb +94 -0
  42. data/lib/insight/panels/templates_panel.rb +58 -0
  43. data/lib/insight/panels/templates_panel/rendering.rb +81 -0
  44. data/lib/insight/panels/timer_panel.rb +40 -0
  45. data/lib/insight/params_signature.rb +61 -0
  46. data/lib/insight/public/__insight__/bookmarklet.html +10 -0
  47. data/lib/insight/public/__insight__/bookmarklet.js +223 -0
  48. data/lib/insight/public/__insight__/insight.css +235 -0
  49. data/lib/insight/public/__insight__/insight.js +123 -0
  50. data/lib/insight/public/__insight__/jquery-1.3.2.js +4376 -0
  51. data/lib/insight/public/__insight__/jquery.tablesorter.min.js +1 -0
  52. data/lib/insight/public/__insight__/spinner.gif +0 -0
  53. data/lib/insight/rack_static_bug_avoider.rb +16 -0
  54. data/lib/insight/redirect_interceptor.rb +25 -0
  55. data/lib/insight/render.rb +72 -0
  56. data/lib/insight/request-recorder.rb +23 -0
  57. data/lib/insight/toolbar.rb +63 -0
  58. data/lib/insight/views/enable-button.html.erb +1 -0
  59. data/lib/insight/views/error.html.erb +17 -0
  60. data/lib/insight/views/headers_fragment.html.erb +20 -0
  61. data/lib/insight/views/panels/active_record.html.erb +17 -0
  62. data/lib/insight/views/panels/cache.html.erb +93 -0
  63. data/lib/insight/views/panels/execute_sql.html.erb +32 -0
  64. data/lib/insight/views/panels/explain_sql.html.erb +32 -0
  65. data/lib/insight/views/panels/log.html.erb +21 -0
  66. data/lib/insight/views/panels/profile_sql.html.erb +32 -0
  67. data/lib/insight/views/panels/rails_info.html.erb +19 -0
  68. data/lib/insight/views/panels/redis.html.erb +46 -0
  69. data/lib/insight/views/panels/request_variables.html.erb +25 -0
  70. data/lib/insight/views/panels/speedtracer/serverevent.html.erb +10 -0
  71. data/lib/insight/views/panels/speedtracer/servertrace.html.erb +12 -0
  72. data/lib/insight/views/panels/speedtracer/traces.html.erb +18 -0
  73. data/lib/insight/views/panels/sql.html.erb +43 -0
  74. data/lib/insight/views/panels/templates.html.erb +6 -0
  75. data/lib/insight/views/panels/timer.html.erb +19 -0
  76. data/lib/insight/views/panels/view_cache.html.erb +19 -0
  77. data/lib/insight/views/redirect.html.erb +16 -0
  78. data/lib/insight/views/request_fragment.html.erb +25 -0
  79. data/lib/insight/views/toolbar.html.erb +29 -0
  80. data/lib/logical-insight.rb +1 -0
  81. data/spec/custom_matchers.rb +31 -0
  82. data/spec/fixtures/config.ru +8 -0
  83. data/spec/fixtures/dummy_panel.rb +2 -0
  84. data/spec/fixtures/sample_app.rb +72 -0
  85. data/spec/insight/panels/active_record_panel_spec.rb +42 -0
  86. data/spec/insight/panels/cache_panel_spec.rb +176 -0
  87. data/spec/insight/panels/log_panel_spec.rb +44 -0
  88. data/spec/insight/panels/memory_panel_spec.rb +19 -0
  89. data/spec/insight/panels/mongo_panel_spec_pending.rb +50 -0
  90. data/spec/insight/panels/rails_info_panel_spec.rb +27 -0
  91. data/spec/insight/panels/redis_panel_spec.rb +66 -0
  92. data/spec/insight/panels/sql_panel_spec.rb +145 -0
  93. data/spec/insight/panels/templates_panel_spec.rb +84 -0
  94. data/spec/insight/panels/timer_panel_spec.rb +36 -0
  95. data/spec/insight_spec.rb +141 -0
  96. data/spec/instrumentation_spec.rb +188 -0
  97. data/spec/rcov.opts +1 -0
  98. data/spec/spec.opts +1 -0
  99. data/spec/spec_helper.rb +93 -0
  100. metadata +187 -0
@@ -0,0 +1,42 @@
1
+ require File::expand_path("../../../spec_helper", __FILE__)
2
+ module Insight
3
+ describe "ActiveRecordPanel" do
4
+ before do
5
+ mock_constant("ActiveRecord::Base")
6
+ reset_insight :panel_classes => [ActiveRecordPanel]
7
+ end
8
+
9
+ def mock_model(name)
10
+ model = stub("model")
11
+ model.stub!(:name => name)
12
+ obj = stub(name)
13
+ obj.stub!(:base_class => model)
14
+ obj
15
+ end
16
+
17
+ describe "heading" do
18
+ it "displays the total number of instantiated AR objects" do
19
+ app.before_return do
20
+ mock_method_call("ActiveRecord::Base", "allocate", [], :class, mock_model("User"))
21
+ mock_method_call("ActiveRecord::Base", "allocate", [], :class, mock_model("Group"))
22
+ end
23
+
24
+ response = get_via_rack "/"
25
+ response.should have_heading("2 AR Objects")
26
+ end
27
+ end
28
+
29
+ describe "content" do
30
+ it "displays the count of instantiated objects for each class" do
31
+ app.before_return do
32
+ mock_method_call("ActiveRecord::Base", "allocate", [], :class, mock_model("User"))
33
+ mock_method_call("ActiveRecord::Base", "allocate", [], :class, mock_model("User"))
34
+ mock_method_call("ActiveRecord::Base", "allocate", [], :class, mock_model("Group"))
35
+ end
36
+ response = get_via_rack "/"
37
+ response.should have_row("#active_record", "User", "2")
38
+ response.should have_row("#active_record", "Group", "1")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,176 @@
1
+ module Insight
2
+ describe "CachePanel" do
3
+ before do
4
+ mock_constant("Rails")
5
+ mock_constant("Memcached")
6
+ mock_constant("MemCache")
7
+ reset_insight :panel_classes => [CachePanel]
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the total memcache time" do
12
+ response = get_via_rack "/"
13
+ response.should have_heading("Cache: 0.00ms")
14
+ end
15
+ end
16
+
17
+ describe "content" do
18
+ describe "usage table" do
19
+ it "displays the total number of memcache calls" do
20
+ app.before_return do
21
+ mock_method_call("Memcached", "get", ["user:1"])
22
+ end
23
+ response = get_via_rack "/"
24
+
25
+ # This causes a bus error:
26
+ # response.should have_selector("th:content('Total Calls') + td", :content => "1")
27
+
28
+ response.should have_row("#cache_usage", "Total Calls", "1")
29
+ end
30
+
31
+ it "displays the total memcache time" do
32
+ response = get_via_rack "/"
33
+ response.should have_row("#cache_usage", "Total Time", "0.00ms")
34
+ end
35
+
36
+ it "dispays the number of memcache hits" do
37
+ app.before_return do
38
+ mock_method_call("Memcached", "get", ["user:1"])
39
+ end
40
+ response = get_via_rack "/"
41
+ response.should have_row("#cache_usage", "Hits", "0")
42
+ end
43
+
44
+ it "displays the number of memcache misses" do
45
+ app.before_return do
46
+ mock_method_call("Memcached", "get", ["user:1"])
47
+ end
48
+ response = get_via_rack "/"
49
+ response.should have_row("#cache_usage", "Misses", "1")
50
+ end
51
+
52
+ it "displays the number of memcache gets" do
53
+ app.before_return do
54
+ mock_method_call("Memcached", "get", ["user:1"])
55
+ end
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
+
62
+ app.before_return do
63
+ mock_method_call("Memcached", "set", ["user:1"])
64
+ end
65
+ response = get_via_rack "/"
66
+ response.should have_row("#cache_usage", "sets", "1")
67
+ end
68
+
69
+ it "displays the number of memcache deletes" do
70
+ app.before_return do
71
+ mock_method_call("Memcached", "delete", ["user:1"])
72
+ end
73
+ response = get_via_rack "/"
74
+ response.should have_row("#cache_usage", "deletes", "1")
75
+ end
76
+
77
+ it "displays the number of memcache get_multis" do
78
+ app.before_return do
79
+ mock_method_call("MemCache", "get_multi", ["user:1", "user:2"])
80
+ end
81
+ response = get_via_rack "/"
82
+ response.should have_row("#cache_usage", "get_multis", "1")
83
+ end
84
+ end
85
+
86
+ describe "breakdown" do
87
+ it "displays each memcache operation" do
88
+ app.before_return do
89
+ mock_method_call("Memcached", "get", ["user:1"])
90
+ end
91
+ response = get_via_rack "/"
92
+ response.should have_row("#cache_breakdown", "get")
93
+ end
94
+
95
+ it "displays the time for each memcache call" do
96
+ app.before_return do
97
+ mock_method_call("Memcached", "get", ["user:1"])
98
+ end
99
+ response = get_via_rack "/"
100
+ response.should have_row("#cache_breakdown", "user:1", TIME_MS_REGEXP)
101
+ end
102
+
103
+ it "displays the keys for each memcache call" do
104
+ app.before_return do
105
+ mock_method_call("Memcached", "get", ["user:1"])
106
+ end
107
+ response = get_via_rack "/"
108
+ response.should have_row("#cache_breakdown", "user:1", "get")
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "cache operations" do
114
+ before do
115
+ rack_env "insight.secret_key", 'abc'
116
+ response = get_via_rack "/"
117
+ end
118
+
119
+
120
+ describe "expire_all" do
121
+ it "expires the cache keys" do
122
+ Rails.stub!(:cache => mock("cache"))
123
+ Rails.cache.should_receive(:delete).with("user:1")
124
+ Rails.cache.should_receive(:delete).with("user:2")
125
+ Rails.cache.should_receive(:delete).with("user:3")
126
+ Rails.cache.should_receive(:delete).with("user:4")
127
+
128
+ get_via_rack "/__insight__/delete_cache_list",
129
+ :keys_1 => "user:1", :keys_2 => "user:2", :keys_3 => "user:3", :keys_4 => "user:4",
130
+ :hash => Digest::SHA1.hexdigest("abc:user:1:user:2:user:3:user:4")
131
+ end
132
+
133
+ it "returns OK" do
134
+ Rails.stub!(:cache => mock("cache", :delete => nil))
135
+ response = get_via_rack "/__insight__/delete_cache_list",
136
+ :keys_1 => "user:1", :keys_2 => "user:2", :keys_3 => "user:3", :keys_4 => "user:4",
137
+ :hash => Digest::SHA1.hexdigest("abc:user:1:user:2:user:3:user:4")
138
+ response.should contain("OK")
139
+ end
140
+ end
141
+
142
+ describe "expire" do
143
+ it "expires the cache key" do
144
+ Rails.stub!(:cache => mock("cache"))
145
+ Rails.cache.should_receive(:delete).with("user:1")
146
+ get_via_rack "/__insight__/delete_cache", :key => "user:1",
147
+ :hash => Digest::SHA1.hexdigest("abc:user:1")
148
+ end
149
+
150
+ it "returns OK" do
151
+ Rails.stub!(:cache => mock("cache", :delete => nil))
152
+ response = get_via_rack "/__insight__/delete_cache", :key => "user:1",
153
+ :hash => Digest::SHA1.hexdigest("abc:user:1")
154
+ response.should contain("OK")
155
+ end
156
+ end
157
+
158
+ describe "view_cache" do
159
+ it "renders the cache key" do
160
+ Rails.stub!(:cache => mock("cache", :read => "cache body"))
161
+ response = get_via_rack "/__insight__/view_cache", :key => "user:1",
162
+ :hash => Digest::SHA1.hexdigest("abc:user:1")
163
+ response.should contain("cache body")
164
+ end
165
+
166
+ it "renders non-String cache values properly" do
167
+ Rails.stub!(:cache => mock("cache", :read => [1, 2]))
168
+ response = get_via_rack "/__insight__/view_cache", :key => "user:1",
169
+ :hash => Digest::SHA1.hexdigest("abc:user:1")
170
+ response.should contain("[1, 2]")
171
+ end
172
+ end
173
+
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,44 @@
1
+ require File::expand_path('../../../spec_helper', __FILE__)
2
+
3
+ module Insight
4
+ describe "LogPanel" do
5
+ before do
6
+ reset_insight :panel_classes => [LogPanel]
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays 'Log'" do
11
+ response = get_via_rack "/"
12
+ response.should have_heading("Log")
13
+ end
14
+ end
15
+
16
+ describe "content" do
17
+ it "displays recorded log lines" do
18
+ app.before_return do
19
+ mock_method_call("Logger", "add", [0, "This is a logged message"])
20
+ end
21
+ response = get_via_rack "/"
22
+ response.should contain("This is a logged message")
23
+ response.should contain("DEBUG")
24
+ end
25
+ end
26
+
27
+ describe "Extended Logger" do
28
+ it "does still return true/false for #add if class Logger" do
29
+ #AS::BufferedLogger returns the added string, Logger returns true/false
30
+ LOGGER.add(0, "foo").should == true
31
+ end
32
+ end
33
+
34
+
35
+ describe "With no logger defined" do
36
+ it "does not err out" do
37
+ logger = LOGGER
38
+ Object.send :remove_const, :LOGGER
39
+ lambda{ load("insight/panels/log_panel.rb") }.should_not raise_error
40
+ ::LOGGER = logger
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ module Insight
2
+ describe "MemoryPanel" do
3
+ before do
4
+ reset_insight :panel => [MemoryPanel]
5
+ end
6
+
7
+ describe "heading" do
8
+ it "displays the total memory" do
9
+ response = get_via_rack "/"
10
+ response.should have_heading(/\d+ KB total/)
11
+ end
12
+
13
+ it "displays the memory change during the request" do
14
+ response = get_via_rack "/"
15
+ response.should have_heading(/\d+ KB/)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ if defined? Mongo
2
+ module Insight
3
+ describe "MongoPanel" do
4
+ before do
5
+ MongoPanel.reset
6
+ rack_env "insight.panel_classes", [MongoPanel]
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays the total mongo time" do
11
+ response = get_via_rack "/"
12
+ response.should have_heading("Mongo: 0.00ms")
13
+ end
14
+ end
15
+
16
+ describe "content" do
17
+ describe "usage table" do
18
+ it "displays the total number of mongo calls" do
19
+ MongoPanel.record("db.user.user.find()") { }
20
+ response = get_via_rack "/"
21
+
22
+ # This causes a bus error:
23
+ # response.should have_selector("th:content('Total Calls') + td", :content => "1")
24
+
25
+ response.should have_row("#mongo_usage", "Total Calls", "1")
26
+ end
27
+
28
+ it "displays the total mongo time" do
29
+ response = get_via_rack "/"
30
+ response.should have_row("#mongo_usage", "Total Time", "0.00ms")
31
+ end
32
+ end
33
+
34
+ describe "breakdown" do
35
+ it "displays each mongo operation" do
36
+ MongoPanel.record("db.user.user.find()") { }
37
+ response = get_via_rack "/"
38
+ response.should have_row("#mongo_breakdown", "db.user.user.find()")
39
+ end
40
+
41
+ it "displays the time for mongo call" do
42
+ MongoPanel.record("db.user.user.find()") { }
43
+ response = get_via_rack "/"
44
+ response.should have_row("#mongo_breakdown", "db.user.user.find()", TIME_MS_REGEXP)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,27 @@
1
+ module Insight
2
+ describe "RailsInfoPanel" do
3
+ before do
4
+ mock_constant("Rails::Info")
5
+ reset_insight :panel_classes => [RailsInfoPanel]
6
+
7
+ Rails::Info.stub!(:properties => [])
8
+ end
9
+
10
+ describe "heading" do
11
+ it "displays the Rails version" do
12
+ Rails.stub!(:version => "v2.3.0")
13
+ response = get_via_rack "/"
14
+ response.should have_heading("Rails v2.3.0")
15
+ end
16
+ end
17
+
18
+ describe "content" do
19
+ it "displays the Rails::Info properties" do
20
+ Rails.stub!(:version => "v2.3.0")
21
+ Rails::Info.stub!(:properties => [["Name", "Value"]])
22
+ response = get_via_rack "/"
23
+ response.should have_row("#rails_info", "Name", "Value")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,66 @@
1
+ require File::expand_path("../../../spec_helper", __FILE__)
2
+ module Insight
3
+ describe "RedisPanel" do
4
+ before do
5
+ reset_insight :panel_files => %w[redis_panel]
6
+ end
7
+
8
+ describe "heading" do
9
+ it "displays the total redis time" do
10
+ response = get_via_rack "/"
11
+ response.should have_heading("Redis: 0.00ms")
12
+ end
13
+ end
14
+
15
+ describe "content" do
16
+ describe "usage table" do
17
+ it "displays the total number of redis calls" do
18
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
19
+ response = get_via_rack "/"
20
+
21
+ # This causes a bus error:
22
+ # response.should have_selector("th:content('Total Calls') + td", :content => "1")
23
+
24
+ response.should have_row("#redis_usage", "Total Calls", "1")
25
+ end
26
+
27
+ it "displays the total redis time" do
28
+ response = get_via_rack "/"
29
+ response.should have_row("#redis_usage", "Total Time", "0.00ms")
30
+ end
31
+ end
32
+
33
+ describe "breakdown" do
34
+ it "displays each redis operation" do
35
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
36
+ response = get_via_rack "/"
37
+ response.should have_row("#redis_breakdown", "get")
38
+ end
39
+
40
+ it "displays the time for redis call" do
41
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
42
+ response = get_via_rack "/"
43
+ response.should have_row("#redis_breakdown", "user:1", TIME_MS_REGEXP)
44
+ end
45
+
46
+ it "displays the arguments for each redis call" do
47
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
48
+ response = get_via_rack "/"
49
+ response.should have_row("#redis_breakdown", "user:1", "get")
50
+ end
51
+
52
+ it "displays a link to show the backtrace when it's available" do
53
+ RedisPanel.record(["get, user:1"], Kernel.caller) { }
54
+ response = get_via_rack "/"
55
+ response.should have_row("#redis_breakdown", "user:1", "Show Backtrace")
56
+ end
57
+
58
+ it "does not display a link to show the backtrace when it's not available" do
59
+ RedisPanel.record(["get, user:1"], []) { }
60
+ response = get_via_rack "/"
61
+ response.should_not contain("Show Backtrace")
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,145 @@
1
+ require File::expand_path("../../../spec_helper", __FILE__)
2
+ module Insight
3
+ describe "SQLPanel" do
4
+ before do
5
+ mock_constant("ActiveRecord::ConnectionAdapters::MysqlAdapter")
6
+ reset_insight :panel_files => %w{sql_panel}
7
+ end
8
+
9
+ describe "heading" do
10
+ it "displays the total SQL query count" do
11
+ app.before_return do
12
+ mock_method_call("ActiveRecord::ConnectionAdapters::MysqlAdapter", "execute", ["SELECT NOW();"])
13
+ end
14
+ response = get_via_rack "/"
15
+ response.should have_heading("1 Queries")
16
+ end
17
+
18
+ it "displays the total SQL time" do
19
+ app.before_return do
20
+ mock_method_call("ActiveRecord::ConnectionAdapters::MysqlAdapter", "execute", ["SELECT NOW();"])
21
+ end
22
+ response = get_via_rack "/"
23
+ response.should have_heading(/Queries \(\d+\.\d{2}ms\)/)
24
+ end
25
+ end
26
+
27
+ describe "content" do
28
+ it "displays each executed SQL query" do
29
+ app.before_return do
30
+ mock_method_call("ActiveRecord::ConnectionAdapters::MysqlAdapter", "execute", ["SELECT NOW();"])
31
+ end
32
+ response = get_via_rack "/"
33
+ response.should have_row("#sql", "SELECT NOW();")
34
+ end
35
+
36
+ it "displays the time of each executed SQL query" do
37
+ app.before_return do
38
+ mock_method_call("ActiveRecord::ConnectionAdapters::MysqlAdapter", "execute", ["SELECT NOW();"])
39
+ end
40
+ response = get_via_rack "/"
41
+ response.should have_row("#sql", "SELECT NOW();", TIME_MS_REGEXP)
42
+ end
43
+ end
44
+
45
+ def stub_result(results = [[]])
46
+ columns = results.first
47
+ fields = columns.map { |c| stub("field", :name => c) }
48
+ rows = results[1..-1]
49
+
50
+ result = stub("result", :fetch_fields => fields)
51
+ result.stub!(:map).and_yield(rows)
52
+ return result
53
+ end
54
+
55
+ def expect_query(sql, results)
56
+ conn = stub("connection")
57
+ mock_constant("ActiveRecord::Base")
58
+ ActiveRecord::Base.stub!(:connection => conn)
59
+ conn.should_receive(:execute).with(sql).and_return(stub_result(results))
60
+ end
61
+
62
+ describe "sql/execute" do
63
+ it "displays the query results" do
64
+ rack_env "insight.secret_key", "abc"
65
+ expect_query "SELECT username FROM users",
66
+ [["username"],
67
+ ["bryan"]]
68
+
69
+ response = get_via_rack "/__insight__/sql/execute", {:query => "SELECT username FROM users",
70
+ :hash => Digest::SHA1.hexdigest("abc:SELECT username FROM users")}, {:xhr => true}
71
+ response.should contain("SELECT username FROM users")
72
+ response.should be_ok
73
+ end
74
+
75
+ it "is forbidden when the hash is missing or wrong" do
76
+ rack_env "insight.secret_key", 'abc'
77
+
78
+ lambda {
79
+ get_via_rack "/__insight__/sql/execute", {:query => "SELECT username FROM users",
80
+ :hash => "foobar"}, {:xhr => true}
81
+ }.should raise_error(SecurityError)
82
+ end
83
+
84
+ it "is not available when the insight.secret_key is nil" do
85
+ rack_env "insight.secret_key", nil
86
+
87
+ lambda {
88
+ get_via_rack "/__insight__/sql/execute", {:query => "SELECT username FROM users",
89
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"}, {:xhr => true}
90
+ }.should raise_error(SecurityError)
91
+ end
92
+
93
+ it "is not available when the insight.secret_key is an empty string" do
94
+ rack_env "insight.secret_key", ""
95
+
96
+ lambda {
97
+ get_via_rack "/__insight__/sql/execute", {:query => "SELECT username FROM users",
98
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"}, {:xhr => true}
99
+ }.should raise_error(SecurityError)
100
+ end
101
+ end
102
+
103
+ describe "sql/explain" do
104
+ it "displays the query explain plan" do
105
+ rack_env "insight.secret_key", "abc"
106
+ expect_query "EXPLAIN SELECT username FROM users",
107
+ [["table"],
108
+ ["users"]]
109
+
110
+
111
+ response = get_via_rack "/__insight__/sql/explain", :query => "SELECT username FROM users",
112
+ :hash => Digest::SHA1.hexdigest("abc:SELECT username FROM users")
113
+ response.should contain("SELECT username FROM users")
114
+ response.should be_ok
115
+ end
116
+
117
+ it "is forbidden when the hash is missing or wrong" do
118
+ rack_env "insight.secret_key", 'abc'
119
+
120
+ lambda {
121
+ get_via_rack "/__insight__/sql/explain", :query => "SELECT username FROM users",
122
+ :hash => "foobar"
123
+ }.should raise_error(SecurityError)
124
+ end
125
+
126
+ it "is not available when the insight.secret_key is nil" do
127
+ rack_env "insight.secret_key", nil
128
+
129
+ lambda {
130
+ get_via_rack "/__insight__/sql/explain", :query => "SELECT username FROM users",
131
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
132
+ }.should raise_error(SecurityError)
133
+ end
134
+
135
+ it "is not available when the insight.secret_key is an empty string" do
136
+ rack_env "insight.secret_key", ""
137
+
138
+ lambda {
139
+ get_via_rack "/__insight__/sql/explain", :query => "SELECT username FROM users",
140
+ :hash => "6f286f55b75716e5c91f16d77d09fa73b353ebc1"
141
+ }.should raise_error(SecurityError)
142
+ end
143
+ end
144
+ end
145
+ end