cloudtrapper 0.0.2.pre

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 (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
+