cloudtrapper 0.0.2.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +823 -0
  2. data/Gemfile +12 -0
  3. data/Guardfile +6 -0
  4. data/INSTALL +20 -0
  5. data/MIT-LICENSE +22 -0
  6. data/README.md +465 -0
  7. data/README_FOR_HEROKU_ADDON.md +94 -0
  8. data/Rakefile +223 -0
  9. data/SUPPORTED_RAILS_VERSIONS +23 -0
  10. data/TESTING.md +33 -0
  11. data/cloudtrapper.gemspec +35 -0
  12. data/features/metal.feature +18 -0
  13. data/features/rack.feature +56 -0
  14. data/features/rails.feature +211 -0
  15. data/features/rails_with_js_notifier.feature +97 -0
  16. data/features/rake.feature +27 -0
  17. data/features/sinatra.feature +29 -0
  18. data/features/step_definitions/file_steps.rb +10 -0
  19. data/features/step_definitions/metal_steps.rb +23 -0
  20. data/features/step_definitions/rack_steps.rb +23 -0
  21. data/features/step_definitions/rails_application_steps.rb +433 -0
  22. data/features/step_definitions/rake_steps.rb +17 -0
  23. data/features/support/airbrake_shim.rb.template +11 -0
  24. data/features/support/env.rb +18 -0
  25. data/features/support/matchers.rb +35 -0
  26. data/features/support/rails.rb +201 -0
  27. data/features/support/rake/Rakefile +68 -0
  28. data/features/support/terminal.rb +107 -0
  29. data/features/user_informer.feature +63 -0
  30. data/generators/cloudtrapper/airbrake_generator.rb +94 -0
  31. data/generators/cloudtrapper/lib/insert_commands.rb +34 -0
  32. data/generators/cloudtrapper/lib/rake_commands.rb +24 -0
  33. data/generators/cloudtrapper/templates/capistrano_hook.rb +6 -0
  34. data/generators/cloudtrapper/templates/cloudtrapper_tasks.rake +25 -0
  35. data/generators/cloudtrapper/templates/initializer.rb +6 -0
  36. data/install.rb +1 -0
  37. data/lib/cloudtrapper/backtrace.rb +100 -0
  38. data/lib/cloudtrapper/capistrano.rb +44 -0
  39. data/lib/cloudtrapper/configuration.rb +281 -0
  40. data/lib/cloudtrapper/notice.rb +348 -0
  41. data/lib/cloudtrapper/rack.rb +55 -0
  42. data/lib/cloudtrapper/rails/action_controller_catcher.rb +30 -0
  43. data/lib/cloudtrapper/rails/controller_methods.rb +74 -0
  44. data/lib/cloudtrapper/rails/error_lookup.rb +33 -0
  45. data/lib/cloudtrapper/rails/javascript_notifier.rb +48 -0
  46. data/lib/cloudtrapper/rails/middleware/exceptions_catcher.rb +29 -0
  47. data/lib/cloudtrapper/rails.rb +40 -0
  48. data/lib/cloudtrapper/rails3_tasks.rb +85 -0
  49. data/lib/cloudtrapper/railtie.rb +48 -0
  50. data/lib/cloudtrapper/rake_handler.rb +66 -0
  51. data/lib/cloudtrapper/sender.rb +116 -0
  52. data/lib/cloudtrapper/shared_tasks.rb +36 -0
  53. data/lib/cloudtrapper/tasks.rb +83 -0
  54. data/lib/cloudtrapper/user_informer.rb +27 -0
  55. data/lib/cloudtrapper/version.rb +3 -0
  56. data/lib/cloudtrapper.rb +155 -0
  57. data/lib/cloudtrapper_tasks.rb +65 -0
  58. data/lib/rails/generators/cloudtrapper/cloudtrapper_generator.rb +100 -0
  59. data/lib/templates/javascript_notifier.erb +15 -0
  60. data/lib/templates/rescue.erb +91 -0
  61. data/rails/init.rb +1 -0
  62. data/resources/README.md +34 -0
  63. data/resources/ca-bundle.crt +3376 -0
  64. data/script/integration_test.rb +38 -0
  65. data/test/backtrace_test.rb +162 -0
  66. data/test/capistrano_test.rb +34 -0
  67. data/test/catcher_test.rb +333 -0
  68. data/test/cloudtrapper_2_2.xsd +78 -0
  69. data/test/cloudtrapper_tasks_test.rb +170 -0
  70. data/test/configuration_test.rb +221 -0
  71. data/test/helper.rb +263 -0
  72. data/test/javascript_notifier_test.rb +52 -0
  73. data/test/logger_test.rb +73 -0
  74. data/test/notice_test.rb +468 -0
  75. data/test/notifier_test.rb +246 -0
  76. data/test/rack_test.rb +58 -0
  77. data/test/rails_initializer_test.rb +36 -0
  78. data/test/recursion_test.rb +10 -0
  79. data/test/sender_test.rb +261 -0
  80. data/test/user_informer_test.rb +29 -0
  81. metadata +301 -0
@@ -0,0 +1,170 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'rubygems'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/cloudtrapper_tasks'
5
+ require 'fakeweb'
6
+
7
+ FakeWeb.allow_net_connect = false
8
+
9
+ class CloudtrapperTasksTest < Test::Unit::TestCase
10
+ def successful_response(body = "")
11
+ response = Net::HTTPSuccess.new('1.2', '200', 'OK')
12
+ response.stubs(:body).returns(body)
13
+ return response
14
+ end
15
+
16
+ def unsuccessful_response(body = "")
17
+ response = Net::HTTPClientError.new('1.2', '200', 'OK')
18
+ response.stubs(:body).returns(body)
19
+ return response
20
+ end
21
+
22
+ context "being quiet" do
23
+ setup { CloudtrapperTasks.stubs(:puts) }
24
+
25
+ context "in a configured project" do
26
+ setup { Cloudtrapper.configure { |config| config.api_key = "1234123412341234" } }
27
+
28
+ context "on deploy({})" do
29
+ setup { @output = CloudtrapperTasks.deploy({}) }
30
+
31
+ before_should "complain about missing rails env" do
32
+ CloudtrapperTasks.expects(:puts).with(regexp_matches(/rails environment/i))
33
+ end
34
+
35
+ should "return false" do
36
+ assert !@output
37
+ end
38
+ end
39
+
40
+ context "given an optional HTTP proxy and valid options" do
41
+ setup do
42
+ @response = stub("response", :body => "stub body")
43
+ @http_proxy = stub("proxy", :request => @response)
44
+ @http_proxy_class = stub("proxy_class", :new => @http_proxy)
45
+ @post = stub("post", :set_form_data => nil)
46
+
47
+ Net::HTTP.expects(:Proxy).
48
+ with(Cloudtrapper.configuration.proxy_host,
49
+ Cloudtrapper.configuration.proxy_port,
50
+ Cloudtrapper.configuration.proxy_user,
51
+ Cloudtrapper.configuration.proxy_pass).
52
+ returns(@http_proxy_class)
53
+ Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
54
+
55
+ @options = { :rails_env => "staging", :dry_run => false }
56
+ end
57
+
58
+ context "performing a dry run" do
59
+ setup { @output = CloudtrapperTasks.deploy(@options.merge(:dry_run => true)) }
60
+
61
+ should "return true without performing any actual request" do
62
+ assert_equal true, @output
63
+ assert_received(@http_proxy, :request) do |expects|
64
+ expects.never
65
+ end
66
+ end
67
+ end
68
+
69
+ context "on deploy(options)" do
70
+ setup do
71
+ @output = CloudtrapperTasks.deploy(@options)
72
+ end
73
+
74
+ before_should "post to http://api.cloudtrapper.io:80/deploys.txt" do
75
+ @http_proxy_class.expects(:new).with("api.cloudtrapper.io", 80).returns(@http_proxy)
76
+ @post.expects(:set_form_data).with(kind_of(Hash))
77
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response)
78
+ end
79
+
80
+ before_should "use the project api key" do
81
+ @post.expects(:set_form_data).
82
+ with(has_entries('api_key' => "1234123412341234"))
83
+ end
84
+
85
+ before_should "use send the rails_env param" do
86
+ @post.expects(:set_form_data).
87
+ with(has_entries("deploy[rails_env]" => "staging"))
88
+ end
89
+
90
+ [:local_username, :scm_repository, :scm_revision].each do |key|
91
+ before_should "use send the #{key} param if it's passed in." do
92
+ @options[key] = "value"
93
+ @post.expects(:set_form_data).
94
+ with(has_entries("deploy[#{key}]" => "value"))
95
+ end
96
+ end
97
+
98
+ before_should "use the :api_key param if it's passed in." do
99
+ @options[:api_key] = "value"
100
+ @post.expects(:set_form_data).
101
+ with(has_entries("api_key" => "value"))
102
+ end
103
+
104
+ before_should "puts the response body on success" do
105
+ CloudtrapperTasks.expects(:puts).with("body")
106
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
107
+ end
108
+
109
+ before_should "puts the response body on failure" do
110
+ CloudtrapperTasks.expects(:puts).with("body")
111
+ @http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
112
+ end
113
+
114
+ should "return false on failure", :before => lambda {
115
+ @http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
116
+ } do
117
+ assert !@output
118
+ end
119
+
120
+ should "return true on success", :before => lambda {
121
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
122
+ } do
123
+ assert @output
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ context "in a configured project with custom host" do
130
+ setup do
131
+ Cloudtrapper.configure do |config|
132
+ config.api_key = "1234123412341234"
133
+ config.host = "custom.host"
134
+ end
135
+ end
136
+
137
+ context "on deploy(:rails_env => 'staging')" do
138
+ setup { @output = CloudtrapperTasks.deploy(:rails_env => "staging") }
139
+
140
+ before_should "post to the custom host" do
141
+ @post = stub("post", :set_form_data => nil)
142
+ @http_proxy = stub("proxy", :request => @response)
143
+
144
+ @http_proxy_class = stub("proxy_class", :new => @http_proxy)
145
+ @http_proxy_class.expects(:new).with("custom.host", 80).returns(@http_proxy)
146
+ Net::HTTP.expects(:Proxy).with(any_parameters).returns(@http_proxy_class)
147
+ Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
148
+ @post.expects(:set_form_data).with(kind_of(Hash))
149
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response)
150
+ end
151
+ end
152
+ end
153
+
154
+ context "when not configured" do
155
+ setup { Cloudtrapper.configure { |config| config.api_key = "" } }
156
+
157
+ context "on deploy(:rails_env => 'staging')" do
158
+ setup { @output = CloudtrapperTasks.deploy(:rails_env => "staging") }
159
+
160
+ before_should "complain about missing api key" do
161
+ CloudtrapperTasks.expects(:puts).with(regexp_matches(/api key/i))
162
+ end
163
+
164
+ should "return false" do
165
+ assert !@output
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,221 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ConfigurationTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ should "provide default values" do
8
+ assert_config_default :proxy_host, nil
9
+ assert_config_default :proxy_port, nil
10
+ assert_config_default :proxy_user, nil
11
+ assert_config_default :proxy_pass, nil
12
+ assert_config_default :project_root, nil
13
+ assert_config_default :environment_name, nil
14
+ assert_config_default :logger, nil
15
+ assert_config_default :notifier_version, Cloudtrapper::VERSION
16
+ assert_config_default :notifier_name, 'Cloudtrapper Notifier'
17
+ assert_config_default :notifier_url, 'https://github.com/cloudtrapper/cloudtrapper'
18
+ assert_config_default :secure, false
19
+ assert_config_default :host, 'api.cloudtrapper.io'
20
+ assert_config_default :http_open_timeout, 2
21
+ assert_config_default :http_read_timeout, 5
22
+ assert_config_default :ignore_by_filters, []
23
+ assert_config_default :ignore_user_agent, []
24
+ assert_config_default :params_filters,
25
+ Cloudtrapper::Configuration::DEFAULT_PARAMS_FILTERS
26
+ assert_config_default :backtrace_filters,
27
+ Cloudtrapper::Configuration::DEFAULT_BACKTRACE_FILTERS
28
+ assert_config_default :ignore,
29
+ Cloudtrapper::Configuration::IGNORE_DEFAULT
30
+ assert_config_default :development_lookup, true
31
+ assert_config_default :framework, 'Standalone'
32
+ end
33
+
34
+ should "provide default values for secure connections" do
35
+ config = Cloudtrapper::Configuration.new
36
+ config.secure = true
37
+ assert_equal 443, config.port
38
+ assert_equal 'https', config.protocol
39
+ end
40
+
41
+ should "provide default values for insecure connections" do
42
+ config = Cloudtrapper::Configuration.new
43
+ config.secure = false
44
+ assert_equal 80, config.port
45
+ assert_equal 'http', config.protocol
46
+ end
47
+
48
+ should "not cache inferred ports" do
49
+ config = Cloudtrapper::Configuration.new
50
+ config.secure = false
51
+ config.port
52
+ config.secure = true
53
+ assert_equal 443, config.port
54
+ end
55
+
56
+ should "allow values to be overwritten" do
57
+ assert_config_overridable :proxy_host
58
+ assert_config_overridable :proxy_port
59
+ assert_config_overridable :proxy_user
60
+ assert_config_overridable :proxy_pass
61
+ assert_config_overridable :secure
62
+ assert_config_overridable :host
63
+ assert_config_overridable :port
64
+ assert_config_overridable :http_open_timeout
65
+ assert_config_overridable :http_read_timeout
66
+ assert_config_overridable :project_root
67
+ assert_config_overridable :notifier_version
68
+ assert_config_overridable :notifier_name
69
+ assert_config_overridable :notifier_url
70
+ assert_config_overridable :environment_name
71
+ assert_config_overridable :development_lookup
72
+ assert_config_overridable :logger
73
+ end
74
+
75
+ should "have an api key" do
76
+ assert_config_overridable :api_key
77
+ end
78
+
79
+ should "act like a hash" do
80
+ config = Cloudtrapper::Configuration.new
81
+ hash = config.to_hash
82
+ [:api_key, :backtrace_filters, :development_environments,
83
+ :environment_name, :host, :http_open_timeout,
84
+ :http_read_timeout, :ignore, :ignore_by_filters, :ignore_user_agent,
85
+ :notifier_name, :notifier_url, :notifier_version, :params_filters,
86
+ :project_root, :port, :protocol, :proxy_host, :proxy_pass, :proxy_port,
87
+ :proxy_user, :secure, :development_lookup].each do |option|
88
+ assert_equal config[option], hash[option], "Wrong value for #{option}"
89
+ end
90
+ end
91
+
92
+ should "be mergable" do
93
+ config = Cloudtrapper::Configuration.new
94
+ hash = config.to_hash
95
+ assert_equal hash.merge(:key => 'value'), config.merge(:key => 'value')
96
+ end
97
+
98
+ should "allow param filters to be appended" do
99
+ assert_appends_value :params_filters
100
+ end
101
+
102
+ should "warn when attempting to read environment filters" do
103
+ config = Cloudtrapper::Configuration.new
104
+ config.
105
+ expects(:warn).
106
+ with(regexp_matches(/deprecated/i))
107
+ assert_equal [], config.environment_filters
108
+ end
109
+
110
+ should "warn when attempting to write js_notifier" do
111
+ config = Cloudtrapper::Configuration.new
112
+ config.
113
+ expects(:warn).
114
+ with(regexp_matches(/deprecated/i))
115
+ config.js_notifier = true
116
+ end
117
+
118
+ should "allow ignored user agents to be appended" do
119
+ assert_appends_value :ignore_user_agent
120
+ end
121
+
122
+ should "allow backtrace filters to be appended" do
123
+ assert_appends_value(:backtrace_filters) do |config|
124
+ new_filter = lambda {}
125
+ config.filter_backtrace(&new_filter)
126
+ new_filter
127
+ end
128
+ end
129
+
130
+ should "allow ignore by filters to be appended" do
131
+ assert_appends_value(:ignore_by_filters) do |config|
132
+ new_filter = lambda {}
133
+ config.ignore_by_filter(&new_filter)
134
+ new_filter
135
+ end
136
+ end
137
+
138
+ should "allow ignored exceptions to be appended" do
139
+ config = Cloudtrapper::Configuration.new
140
+ original_filters = config.ignore.dup
141
+ new_filter = 'hello'
142
+ config.ignore << new_filter
143
+ assert_same_elements original_filters + [new_filter], config.ignore
144
+ end
145
+
146
+ should "allow ignored exceptions to be replaced" do
147
+ assert_replaces(:ignore, :ignore_only=)
148
+ end
149
+
150
+ should "allow ignored user agents to be replaced" do
151
+ assert_replaces(:ignore_user_agent, :ignore_user_agent_only=)
152
+ end
153
+
154
+ should "use development and test as development environments by default" do
155
+ config = Cloudtrapper::Configuration.new
156
+ assert_same_elements %w(development test cucumber), config.development_environments
157
+ end
158
+
159
+ should "be public in a public environment" do
160
+ config = Cloudtrapper::Configuration.new
161
+ config.development_environments = %w(development)
162
+ config.environment_name = 'production'
163
+ assert config.public?
164
+ end
165
+
166
+ should "not be public in a development environment" do
167
+ config = Cloudtrapper::Configuration.new
168
+ config.development_environments = %w(staging)
169
+ config.environment_name = 'staging'
170
+ assert !config.public?
171
+ end
172
+
173
+ should "be public without an environment name" do
174
+ config = Cloudtrapper::Configuration.new
175
+ assert config.public?
176
+ end
177
+
178
+ should "use the assigned logger if set" do
179
+ config = Cloudtrapper::Configuration.new
180
+ config.logger = "CUSTOM LOGGER"
181
+ assert_equal "CUSTOM LOGGER", config.logger
182
+ end
183
+
184
+ should 'give a new instance if non defined' do
185
+ Cloudtrapper.configuration = nil
186
+ assert_kind_of Cloudtrapper::Configuration, Cloudtrapper.configuration
187
+ end
188
+
189
+ def assert_config_default(option, default_value, config = nil)
190
+ config ||= Cloudtrapper::Configuration.new
191
+ assert_equal default_value, config.send(option)
192
+ end
193
+
194
+ def assert_config_overridable(option, value = 'a value')
195
+ config = Cloudtrapper::Configuration.new
196
+ config.send(:"#{option}=", value)
197
+ assert_equal value, config.send(option)
198
+ end
199
+
200
+ def assert_appends_value(option, &block)
201
+ config = Cloudtrapper::Configuration.new
202
+ original_values = config.send(option).dup
203
+ block ||= lambda do |config|
204
+ new_value = 'hello'
205
+ config.send(option) << new_value
206
+ new_value
207
+ end
208
+ new_value = block.call(config)
209
+ assert_same_elements original_values + [new_value], config.send(option)
210
+ end
211
+
212
+ def assert_replaces(option, setter)
213
+ config = Cloudtrapper::Configuration.new
214
+ new_value = 'hello'
215
+ config.send(setter, [new_value])
216
+ assert_equal [new_value], config.send(option)
217
+ config.send(setter, new_value)
218
+ assert_equal [new_value], config.send(option)
219
+ end
220
+
221
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,263 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+ require 'test/unit'
4
+ require 'rubygems'
5
+
6
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
7
+
8
+ require 'thread'
9
+
10
+ require "bundler/setup"
11
+
12
+ require 'shoulda'
13
+ require 'mocha'
14
+
15
+ require 'action_controller'
16
+ require 'action_controller/test_process'
17
+ require 'active_record'
18
+ require 'active_support'
19
+ require 'nokogiri'
20
+ require 'rack'
21
+ require 'bourne'
22
+ require 'sham_rack'
23
+
24
+ require "cloudtrapper"
25
+
26
+ begin require 'redgreen'; rescue LoadError; end
27
+
28
+ module TestMethods
29
+ def rescue_action e
30
+ raise e
31
+ end
32
+
33
+ def do_raise
34
+ raise "Cloudtrapper"
35
+ end
36
+
37
+ def do_not_raise
38
+ render :text => "Success"
39
+ end
40
+
41
+ def do_raise_ignored
42
+ raise ActiveRecord::RecordNotFound.new("404")
43
+ end
44
+
45
+ def do_raise_not_ignored
46
+ raise ActiveRecord::StatementInvalid.new("Statement invalid")
47
+ end
48
+
49
+ def manual_notify
50
+ notify_cloudtrapper(Exception.new)
51
+ render :text => "Success"
52
+ end
53
+
54
+ def manual_notify_ignored
55
+ notify_cloudtrapper(ActiveRecord::RecordNotFound.new("404"))
56
+ render :text => "Success"
57
+ end
58
+ end
59
+
60
+ class Test::Unit::TestCase
61
+ def request(action = nil, method = :get, user_agent = nil, params = {})
62
+ @request = ActionController::TestRequest.new
63
+ @request.action = action ? action.to_s : ""
64
+
65
+ if user_agent
66
+ if @request.respond_to?(:user_agent=)
67
+ @request.user_agent = user_agent
68
+ else
69
+ @request.env["HTTP_USER_AGENT"] = user_agent
70
+ end
71
+ end
72
+ @request.query_parameters = @request.query_parameters.merge(params)
73
+ @response = ActionController::TestResponse.new
74
+ @controller.process(@request, @response)
75
+ end
76
+
77
+ # Borrowed from ActiveSupport 2.3.2
78
+ def assert_difference(expression, difference = 1, message = nil, &block)
79
+ b = block.send(:binding)
80
+ exps = Array.wrap(expression)
81
+ before = exps.map { |e| eval(e, b) }
82
+
83
+ yield
84
+
85
+ exps.each_with_index do |e, i|
86
+ error = "#{e.inspect} didn't change by #{difference}"
87
+ error = "#{message}.\n#{error}" if message
88
+ assert_equal(before[i] + difference, eval(e, b), error)
89
+ end
90
+ end
91
+
92
+ def assert_no_difference(expression, message = nil, &block)
93
+ assert_difference expression, 0, message, &block
94
+ end
95
+
96
+ def stub_sender
97
+ stub('sender', :send_to_cloudtrapper => nil)
98
+ end
99
+
100
+ def stub_sender!
101
+ Cloudtrapper.sender = stub_sender
102
+ end
103
+
104
+ def stub_notice
105
+ stub('notice', :to_xml => 'some yaml', :ignore? => false)
106
+ end
107
+
108
+ def stub_notice!
109
+ stub_notice.tap do |notice|
110
+ Cloudtrapper::Notice.stubs(:new => notice)
111
+ end
112
+ end
113
+
114
+ def create_dummy
115
+ Cloudtrapper::DummySender.new
116
+ end
117
+
118
+ def reset_config
119
+ Cloudtrapper.configuration = nil
120
+ Cloudtrapper.configure do |config|
121
+ config.api_key = 'abc123'
122
+ end
123
+ end
124
+
125
+ def clear_backtrace_filters
126
+ Cloudtrapper.configuration.backtrace_filters.clear
127
+ end
128
+
129
+ def build_exception(opts = {})
130
+ backtrace = ["cloudtrapper/test/helper.rb:132:in `build_exception'",
131
+ "cloudtrapper/test/backtrace.rb:4:in `build_notice_data'",
132
+ "/var/lib/gems/1.8/gems/cloudtrapper-2.4.5/rails/init.rb:2:in `send_exception'"]
133
+ opts = {:backtrace => backtrace}.merge(opts)
134
+ BacktracedException.new(opts)
135
+ end
136
+
137
+ class BacktracedException < Exception
138
+ attr_accessor :backtrace
139
+ def initialize(opts)
140
+ @backtrace = opts[:backtrace]
141
+ end
142
+ def set_backtrace(bt)
143
+ @backtrace = bt
144
+ end
145
+ end
146
+
147
+ def build_notice_data(exception = nil)
148
+ exception ||= build_exception
149
+ {
150
+ :api_key => 'abc123',
151
+ :error_class => exception.class.name,
152
+ :error_message => "#{exception.class.name}: #{exception.message}",
153
+ :backtrace => exception.backtrace,
154
+ :environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
155
+ :request => {
156
+ :params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
157
+ :rails_root => '/path/to/application',
158
+ :url => "http://test.host/users/1"
159
+ },
160
+ :session => {
161
+ :key => '123abc',
162
+ :data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
163
+ }
164
+ }
165
+ end
166
+
167
+ def assert_caught_and_sent
168
+ assert !Cloudtrapper.sender.collected.empty?
169
+ end
170
+
171
+ def assert_caught_and_not_sent
172
+ assert Cloudtrapper.sender.collected.empty?
173
+ end
174
+
175
+ def assert_array_starts_with(expected, actual)
176
+ assert_respond_to actual, :to_ary
177
+ array = actual.to_ary.reverse
178
+ expected.reverse.each_with_index do |value, i|
179
+ assert_equal value, array[i]
180
+ end
181
+ end
182
+
183
+ def assert_valid_node(document, xpath, content)
184
+ nodes = document.xpath(xpath)
185
+ assert nodes.any?{|node| node.content == content },
186
+ "Expected xpath #{xpath} to have content #{content}, " +
187
+ "but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
188
+ "Document:\n#{document.to_s}"
189
+ end
190
+
191
+ def assert_logged(expected)
192
+ assert_received(Cloudtrapper, :write_verbose_log) do |expect|
193
+ expect.with {|actual| actual =~ expected }
194
+ end
195
+ end
196
+
197
+ def assert_not_logged(expected)
198
+ assert_received(Cloudtrapper, :write_verbose_log) do |expect|
199
+ expect.with {|actual| actual =~ expected }.never
200
+ end
201
+ end
202
+
203
+
204
+ end
205
+
206
+ module DefinesConstants
207
+ def setup
208
+ @defined_constants = []
209
+ end
210
+
211
+ def teardown
212
+ @defined_constants.each do |constant|
213
+ Object.__send__(:remove_const, constant)
214
+ end
215
+ end
216
+
217
+ def define_constant(name, value)
218
+ Object.const_set(name, value)
219
+ @defined_constants << name
220
+ end
221
+ end
222
+
223
+ # Also stolen from AS 2.3.2
224
+ class Array
225
+ # Wraps the object in an Array unless it's an Array. Converts the
226
+ # object to an Array using #to_ary if it implements that.
227
+ def self.wrap(object)
228
+ case object
229
+ when nil
230
+ []
231
+ when self
232
+ object
233
+ else
234
+ if object.respond_to?(:to_ary)
235
+ object.to_ary
236
+ else
237
+ [object]
238
+ end
239
+ end
240
+ end
241
+
242
+ end
243
+
244
+ class CollectingSender
245
+ attr_reader :collected
246
+
247
+ def initialize
248
+ @collected = []
249
+ end
250
+
251
+ def send_to_cloudtrapper(data)
252
+ @collected << data
253
+ end
254
+ end
255
+
256
+ class FakeLogger
257
+ def info(*args); end
258
+ def debug(*args); end
259
+ def warn(*args); end
260
+ def error(*args); end
261
+ def fatal(*args); end
262
+ end
263
+
@@ -0,0 +1,52 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'cloudtrapper/rails/javascript_notifier'
3
+ require 'ostruct'
4
+
5
+ class JavascriptNotifierTest < Test::Unit::TestCase
6
+ module FakeRenderer
7
+ def javascript_tag(text)
8
+ "<script>#{text}</script>"
9
+ end
10
+ def escape_javascript(text)
11
+ "ESC#{text}ESC"
12
+ end
13
+ end
14
+
15
+ class FakeController
16
+ def self.helper_method(*args)
17
+ end
18
+
19
+ include Cloudtrapper::Rails::JavascriptNotifier
20
+
21
+ def action_name
22
+ "action"
23
+ end
24
+
25
+ def controller_name
26
+ "controller"
27
+ end
28
+
29
+ def request
30
+ @request ||= OpenStruct.new
31
+ end
32
+
33
+ def render_to_string(options)
34
+ context = OpenStruct.new(options[:locals])
35
+ context.extend(FakeRenderer)
36
+ context.instance_eval do
37
+ erb = ERB.new(IO.read(options[:file]))
38
+ erb.result(binding)
39
+ end
40
+ end
41
+ end
42
+
43
+ should "make sure escape_javacript is called on the request.url" do
44
+ Cloudtrapper.configure do
45
+ end
46
+ controller = FakeController.new
47
+ controller.request.url = "bad_javascript"
48
+ assert controller.send(:cloudtrapper_javascript_notifier)['"ESCbad_javascriptESC"']
49
+ assert ! controller.send(:cloudtrapper_javascript_notifier)['"bad_javascript"']
50
+ end
51
+ end
52
+