hydraulic_brake 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+ require 'fileutils'
5
+
6
+ RAILS_ENV = "production"
7
+ RAILS_ROOT = FileUtils.pwd
8
+ RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
9
+
10
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+ require 'hydraulic_brake'
12
+
13
+ fail "Please supply an API Key as the first argument" if ARGV.empty?
14
+
15
+ host = ARGV[1]
16
+
17
+ secure = (ARGV[2] == "secure")
18
+
19
+ exception = begin
20
+ raise "Testing hydraulic brake notifier with secure = #{secure}. If you can see this, it works."
21
+ rescue => foo
22
+ foo
23
+ end
24
+
25
+ HydraulicBrake.configure do |config|
26
+ config.secure = secure
27
+ config.host = host
28
+ config.api_key = ARGV.first
29
+ end
30
+ puts "Configuration:"
31
+ HydraulicBrake.configuration.to_hash.each do |key, value|
32
+ puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
33
+ end
34
+ puts "Sending #{secure ? "" : "in"}secure notification to project with key #{ARGV.first}"
35
+ HydraulicBrake.notify(exception)
36
+
@@ -0,0 +1,88 @@
1
+ <?xml version="1.0"?>
2
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
+
4
+ <xs:element name="notice">
5
+ <xs:complexType>
6
+ <xs:all>
7
+ <xs:element name="api-key" type="xs:string"/>
8
+ <xs:element name="notifier" type="notifier"/>
9
+ <xs:element name="error" type="error"/>
10
+ <xs:element name="request" type="request" minOccurs="0"/>
11
+ <xs:element name="server-environment" type="serverEnvironment"/>
12
+ <xs:element name="current-user" type="current-user" minOccurs="0"/>
13
+ </xs:all>
14
+ <xs:attribute name="version" type="xs:string" use="required"/>
15
+ </xs:complexType>
16
+ </xs:element>
17
+
18
+ <xs:complexType name="notifier">
19
+ <xs:all>
20
+ <xs:element name="name" type="xs:string"/>
21
+ <xs:element name="version" type="xs:string"/>
22
+ <xs:element name="url" type="xs:string"/>
23
+ </xs:all>
24
+ </xs:complexType>
25
+
26
+ <xs:complexType name="error">
27
+ <xs:all>
28
+ <xs:element name="class" type="xs:string"/>
29
+ <xs:element name="message" type="xs:string" minOccurs="0"/>
30
+ <xs:element name="backtrace" type="backtrace"/>
31
+ </xs:all>
32
+ </xs:complexType>
33
+
34
+ <xs:complexType name="backtrace">
35
+ <xs:sequence>
36
+ <xs:element name="line" maxOccurs="unbounded" minOccurs="0">
37
+ <xs:complexType>
38
+ <xs:attribute name="file" type="xs:string" use="required"/>
39
+ <xs:attribute name="number" type="xs:string" use="required"/>
40
+ <xs:attribute name="method" type="xs:string" use="optional"/>
41
+ </xs:complexType>
42
+ </xs:element>
43
+ </xs:sequence>
44
+ </xs:complexType>
45
+
46
+ <xs:complexType name="request">
47
+ <xs:all>
48
+ <xs:element name="url" type="xs:string"/>
49
+ <xs:element name="component" type="xs:string"/>
50
+ <xs:element name="action" type="xs:string" minOccurs="0"/>
51
+ <xs:element name="params" type="varList" minOccurs="0"/>
52
+ <xs:element name="session" type="varList" minOccurs="0"/>
53
+ <xs:element name="cgi-data" type="varList" minOccurs="0"/>
54
+ </xs:all>
55
+ </xs:complexType>
56
+
57
+ <xs:complexType name="varList">
58
+ <xs:sequence>
59
+ <xs:element name="var" type="var" maxOccurs="unbounded"/>
60
+ </xs:sequence>
61
+ </xs:complexType>
62
+
63
+ <xs:complexType name="var" mixed="true">
64
+ <xs:sequence>
65
+ <xs:element name="var" type="var" minOccurs="0" maxOccurs="unbounded"/>
66
+ </xs:sequence>
67
+ <xs:attribute name="key" type="xs:string" use="required"/>
68
+ </xs:complexType>
69
+
70
+ <xs:complexType name="serverEnvironment">
71
+ <xs:sequence>
72
+ <xs:element name="project-root" type="xs:string" minOccurs="0"/>
73
+ <xs:element name="environment-name" type="xs:string"/>
74
+ <xs:element name="app-version" type="xs:string" minOccurs="0"/>
75
+ <xs:element name="hostname" type="xs:string" minOccurs="0"/>
76
+ </xs:sequence>
77
+ </xs:complexType>
78
+
79
+ <xs:complexType name="current-user">
80
+ <xs:all>
81
+ <xs:element name="id" type="xs:string"/>
82
+ <xs:element name="name" type="xs:string" minOccurs="0"/>
83
+ <xs:element name="email" type="xs:string" minOccurs="0"/>
84
+ <xs:element name="username" type="xs:string" minOccurs="0"/>
85
+ </xs:all>
86
+ </xs:complexType>
87
+
88
+ </xs:schema>
@@ -0,0 +1,162 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class BacktraceTest < Test::Unit::TestCase
4
+
5
+ should "parse a backtrace into lines" do
6
+ array = [
7
+ "app/models/user.rb:13:in `magic'",
8
+ "app/controllers/users_controller.rb:8:in `index'"
9
+ ]
10
+
11
+ backtrace = HydraulicBrake::Backtrace.parse(array)
12
+
13
+ line = backtrace.lines.first
14
+ assert_equal '13', line.number
15
+ assert_equal 'app/models/user.rb', line.file
16
+ assert_equal 'magic', line.method
17
+
18
+ line = backtrace.lines.last
19
+ assert_equal '8', line.number
20
+ assert_equal 'app/controllers/users_controller.rb', line.file
21
+ assert_equal 'index', line.method
22
+ end
23
+
24
+ should "parse a windows backtrace into lines" do
25
+ array = [
26
+ "C:/Program Files/Server/app/models/user.rb:13:in `magic'",
27
+ "C:/Program Files/Server/app/controllers/users_controller.rb:8:in `index'"
28
+ ]
29
+
30
+ backtrace = HydraulicBrake::Backtrace.parse(array)
31
+
32
+ line = backtrace.lines.first
33
+ assert_equal '13', line.number
34
+ assert_equal 'C:/Program Files/Server/app/models/user.rb', line.file
35
+ assert_equal 'magic', line.method
36
+
37
+ line = backtrace.lines.last
38
+ assert_equal '8', line.number
39
+ assert_equal 'C:/Program Files/Server/app/controllers/users_controller.rb', line.file
40
+ assert_equal 'index', line.method
41
+ end
42
+
43
+ should "be equal with equal lines" do
44
+ one = build_backtrace_array
45
+ two = one.dup
46
+
47
+ assert_equal HydraulicBrake::Backtrace.parse(one), HydraulicBrake::Backtrace.parse(two)
48
+ end
49
+
50
+ should "parse massive one-line exceptions into multiple lines" do
51
+ original_backtrace = HydraulicBrake::Backtrace.
52
+ parse(["one:1:in `one'\n two:2:in `two'\n three:3:in `three`"])
53
+ expected_backtrace = HydraulicBrake::Backtrace.
54
+ parse(["one:1:in `one'", "two:2:in `two'", "three:3:in `three`"])
55
+
56
+ assert_equal expected_backtrace, original_backtrace
57
+ end
58
+
59
+ context "with a project root" do
60
+ setup do
61
+ @project_root = '/some/path'
62
+ HydraulicBrake.configure {|config| config.project_root = @project_root }
63
+ end
64
+
65
+ teardown do
66
+ reset_config
67
+ end
68
+
69
+ should "filter out the project root" do
70
+ backtrace_with_root = HydraulicBrake::Backtrace.parse(
71
+ ["#{@project_root}/app/models/user.rb:7:in `latest'",
72
+ "#{@project_root}/app/controllers/users_controller.rb:13:in `index'",
73
+ "/lib/something.rb:41:in `open'"],
74
+ :filters => default_filters)
75
+ backtrace_without_root = HydraulicBrake::Backtrace.parse(
76
+ ["[PROJECT_ROOT]/app/models/user.rb:7:in `latest'",
77
+ "[PROJECT_ROOT]/app/controllers/users_controller.rb:13:in `index'",
78
+ "/lib/something.rb:41:in `open'"])
79
+
80
+ assert_equal backtrace_without_root, backtrace_with_root
81
+ end
82
+ end
83
+
84
+ context "with a project root equals to a part of file name" do
85
+ setup do
86
+ # Heroku-like
87
+ @project_root = '/app'
88
+ HydraulicBrake.configure {|config| config.project_root = @project_root }
89
+ end
90
+
91
+ teardown do
92
+ reset_config
93
+ end
94
+
95
+ should "filter out the project root" do
96
+ backtrace_with_root = HydraulicBrake::Backtrace.parse(
97
+ ["#{@project_root}/app/models/user.rb:7:in `latest'",
98
+ "#{@project_root}/app/controllers/users_controller.rb:13:in `index'",
99
+ "/lib/something.rb:41:in `open'"],
100
+ :filters => default_filters)
101
+ backtrace_without_root = HydraulicBrake::Backtrace.parse(
102
+ ["[PROJECT_ROOT]/app/models/user.rb:7:in `latest'",
103
+ "[PROJECT_ROOT]/app/controllers/users_controller.rb:13:in `index'",
104
+ "/lib/something.rb:41:in `open'"])
105
+
106
+ assert_equal backtrace_without_root, backtrace_with_root
107
+ end
108
+ end
109
+
110
+ context "with a blank project root" do
111
+ setup do
112
+ HydraulicBrake.configure {|config| config.project_root = '' }
113
+ end
114
+
115
+ teardown do
116
+ reset_config
117
+ end
118
+
119
+ should "not filter line numbers with respect to any project root" do
120
+ backtrace = ["/app/models/user.rb:7:in `latest'",
121
+ "/app/controllers/users_controller.rb:13:in `index'",
122
+ "/lib/something.rb:41:in `open'"]
123
+
124
+ backtrace_with_root =
125
+ HydraulicBrake::Backtrace.parse(backtrace, :filters => default_filters)
126
+
127
+ backtrace_without_root =
128
+ HydraulicBrake::Backtrace.parse(backtrace)
129
+
130
+ assert_equal backtrace_without_root, backtrace_with_root
131
+ end
132
+ end
133
+
134
+ should "remove notifier trace" do
135
+ inside_notifier = ['lib/hydraulic_brake.rb:13:in `voodoo`']
136
+ outside_notifier = ['users_controller:8:in `index`']
137
+
138
+ without_inside = HydraulicBrake::Backtrace.parse(outside_notifier)
139
+ with_inside = HydraulicBrake::Backtrace.parse(inside_notifier + outside_notifier,
140
+ :filters => default_filters)
141
+
142
+ assert_equal without_inside, with_inside
143
+ end
144
+
145
+ should "run filters on the backtrace" do
146
+ filters = [lambda { |line| line.sub('foo', 'bar') }]
147
+ input = HydraulicBrake::Backtrace.parse(["foo:13:in `one'", "baz:14:in `two'"],
148
+ :filters => filters)
149
+ expected = HydraulicBrake::Backtrace.parse(["bar:13:in `one'", "baz:14:in `two'"])
150
+ assert_equal expected, input
151
+ end
152
+
153
+ def build_backtrace_array
154
+ ["app/models/user.rb:13:in `magic'",
155
+ "app/controllers/users_controller.rb:8:in `index'"]
156
+ end
157
+
158
+ def default_filters
159
+ HydraulicBrake::Configuration::DEFAULT_BACKTRACE_FILTERS
160
+ end
161
+
162
+ end
@@ -0,0 +1,178 @@
1
+ require File.expand_path '../helper', __FILE__
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, HydraulicBrake::VERSION
16
+ assert_config_default :notifier_name, 'HydraulicBrake Notifier'
17
+ assert_config_default :notifier_url, 'https://github.com/stevecrozz/hydraulic_brake'
18
+ assert_config_default :secure, false
19
+ assert_config_default :host, 'api.airbrake.io'
20
+ assert_config_default :http_open_timeout, 2
21
+ assert_config_default :http_read_timeout, 5
22
+ assert_config_default :params_filters,
23
+ HydraulicBrake::Configuration::DEFAULT_PARAMS_FILTERS
24
+ assert_config_default :backtrace_filters,
25
+ HydraulicBrake::Configuration::DEFAULT_BACKTRACE_FILTERS
26
+ assert_config_default :rake_environment_filters, []
27
+ assert_config_default :development_lookup, true
28
+ assert_config_default :framework, 'Standalone'
29
+ end
30
+
31
+ should "provide default values for secure connections" do
32
+ config = HydraulicBrake::Configuration.new
33
+ config.secure = true
34
+ assert_equal 443, config.port
35
+ assert_equal 'https', config.protocol
36
+ end
37
+
38
+ should "provide default values for insecure connections" do
39
+ config = HydraulicBrake::Configuration.new
40
+ config.secure = false
41
+ assert_equal 80, config.port
42
+ assert_equal 'http', config.protocol
43
+ end
44
+
45
+ should "not cache inferred ports" do
46
+ config = HydraulicBrake::Configuration.new
47
+ config.secure = false
48
+ config.port
49
+ config.secure = true
50
+ assert_equal 443, config.port
51
+ end
52
+
53
+ should "allow values to be overwritten" do
54
+ assert_config_overridable :proxy_host
55
+ assert_config_overridable :proxy_port
56
+ assert_config_overridable :proxy_user
57
+ assert_config_overridable :proxy_pass
58
+ assert_config_overridable :secure
59
+ assert_config_overridable :host
60
+ assert_config_overridable :port
61
+ assert_config_overridable :http_open_timeout
62
+ assert_config_overridable :http_read_timeout
63
+ assert_config_overridable :project_root
64
+ assert_config_overridable :notifier_version
65
+ assert_config_overridable :notifier_name
66
+ assert_config_overridable :notifier_url
67
+ assert_config_overridable :environment_name
68
+ assert_config_overridable :development_lookup
69
+ assert_config_overridable :logger
70
+ end
71
+
72
+ should "have an api key" do
73
+ assert_config_overridable :api_key
74
+ end
75
+
76
+ should "act like a hash" do
77
+ config = HydraulicBrake::Configuration.new
78
+ hash = config.to_hash
79
+ [:api_key, :backtrace_filters, :development_environments,
80
+ :environment_name, :host, :http_open_timeout,
81
+ :http_read_timeout,
82
+ :notifier_name, :notifier_url, :notifier_version, :params_filters,
83
+ :project_root, :port, :protocol, :proxy_host, :proxy_pass, :proxy_port,
84
+ :proxy_user, :secure, :development_lookup].each do |option|
85
+ assert_equal config[option], hash[option], "Wrong value for #{option}"
86
+ end
87
+ end
88
+
89
+ should "be mergable" do
90
+ config = HydraulicBrake::Configuration.new
91
+ hash = config.to_hash
92
+ assert_equal hash.merge(:key => 'value'), config.merge(:key => 'value')
93
+ end
94
+
95
+ should "allow param filters to be appended" do
96
+ assert_appends_value :params_filters
97
+ end
98
+
99
+ should "allow rake environment filters to be appended" do
100
+ assert_appends_value :rake_environment_filters
101
+ end
102
+
103
+ should "allow backtrace filters to be appended" do
104
+ assert_appends_value(:backtrace_filters) do |config|
105
+ new_filter = lambda {}
106
+ config.filter_backtrace(&new_filter)
107
+ new_filter
108
+ end
109
+ end
110
+
111
+ should "use development and test as development environments by default" do
112
+ config = HydraulicBrake::Configuration.new
113
+ assert_same_elements %w(development test cucumber), config.development_environments
114
+ end
115
+
116
+ should "be public in a public environment" do
117
+ config = HydraulicBrake::Configuration.new
118
+ config.development_environments = %w(development)
119
+ config.environment_name = 'production'
120
+ assert config.public?
121
+ end
122
+
123
+ should "not be public in a development environment" do
124
+ config = HydraulicBrake::Configuration.new
125
+ config.development_environments = %w(staging)
126
+ config.environment_name = 'staging'
127
+ assert !config.public?
128
+ end
129
+
130
+ should "be public without an environment name" do
131
+ config = HydraulicBrake::Configuration.new
132
+ assert config.public?
133
+ end
134
+
135
+ should "use the assigned logger if set" do
136
+ config = HydraulicBrake::Configuration.new
137
+ config.logger = "CUSTOM LOGGER"
138
+ assert_equal "CUSTOM LOGGER", config.logger
139
+ end
140
+
141
+ should 'give a new instance if non defined' do
142
+ HydraulicBrake.configuration = nil
143
+ assert_kind_of HydraulicBrake::Configuration, HydraulicBrake.configuration
144
+ end
145
+
146
+ def assert_config_default(option, default_value, config = nil)
147
+ config ||= HydraulicBrake::Configuration.new
148
+ assert_equal default_value, config.send(option)
149
+ end
150
+
151
+ def assert_config_overridable(option, value = 'a value')
152
+ config = HydraulicBrake::Configuration.new
153
+ config.send(:"#{option}=", value)
154
+ assert_equal value, config.send(option)
155
+ end
156
+
157
+ def assert_appends_value(option, &block)
158
+ config = HydraulicBrake::Configuration.new
159
+ original_values = config.send(option).dup
160
+ block ||= lambda do |config|
161
+ new_value = 'hello'
162
+ config.send(option) << new_value
163
+ new_value
164
+ end
165
+ new_value = block.call(config)
166
+ assert_same_elements original_values + [new_value], config.send(option)
167
+ end
168
+
169
+ def assert_replaces(option, setter)
170
+ config = HydraulicBrake::Configuration.new
171
+ new_value = 'hello'
172
+ config.send(setter, [new_value])
173
+ assert_equal [new_value], config.send(option)
174
+ config.send(setter, new_value)
175
+ assert_equal [new_value], config.send(option)
176
+ end
177
+
178
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,239 @@
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 'shoulda'
9
+ require 'nokogiri'
10
+ require 'bourne'
11
+ require "hydraulic_brake"
12
+
13
+ begin require 'redgreen'; rescue LoadError; end
14
+
15
+ module TestMethods
16
+ def rescue_action e
17
+ raise e
18
+ end
19
+
20
+ def do_raise
21
+ raise "HydraulicBrake"
22
+ end
23
+
24
+ def do_not_raise
25
+ render :text => "Success"
26
+ end
27
+
28
+ def manual_notify
29
+ notify_airbrake(Exception.new)
30
+ render :text => "Success"
31
+ end
32
+ end
33
+
34
+ class Test::Unit::TestCase
35
+ def request(action = nil, method = :get, user_agent = nil, params = {})
36
+ @request = ActionController::TestRequest.new
37
+ @request.action = action ? action.to_s : ""
38
+
39
+ if user_agent
40
+ if @request.respond_to?(:user_agent=)
41
+ @request.user_agent = user_agent
42
+ else
43
+ @request.env["HTTP_USER_AGENT"] = user_agent
44
+ end
45
+ end
46
+ @request.query_parameters = @request.query_parameters.merge(params)
47
+ @response = ActionController::TestResponse.new
48
+ @controller.process(@request, @response)
49
+ end
50
+
51
+ # Borrowed from ActiveSupport 2.3.2
52
+ def assert_difference(expression, difference = 1, message = nil, &block)
53
+ b = block.send(:binding)
54
+ exps = AsArray.wrap(expression)
55
+ before = exps.map { |e| eval(e, b) }
56
+
57
+ yield
58
+
59
+ exps.each_with_index do |e, i|
60
+ error = "#{e.inspect} didn't change by #{difference}"
61
+ error = "#{message}.\n#{error}" if message
62
+ assert_equal(before[i] + difference, eval(e, b), error)
63
+ end
64
+ end
65
+
66
+ def assert_no_difference(expression, message = nil, &block)
67
+ assert_difference expression, 0, message, &block
68
+ end
69
+
70
+ def stub_sender
71
+ stub('sender', :send_to_airbrake => nil)
72
+ end
73
+
74
+ def stub_sender!
75
+ HydraulicBrake.sender = stub_sender
76
+ end
77
+
78
+ def stub_notice
79
+ stub('notice', :to_xml => 'some yaml')
80
+ end
81
+
82
+ def stub_notice!
83
+ stub_notice.tap do |notice|
84
+ HydraulicBrake::Notice.stubs(:new => notice)
85
+ end
86
+ end
87
+
88
+ def create_dummy
89
+ HydraulicBrake::DummySender.new
90
+ end
91
+
92
+ def reset_config
93
+ HydraulicBrake.configuration = nil
94
+ HydraulicBrake.configure do |config|
95
+ config.api_key = 'abc123'
96
+ end
97
+ end
98
+
99
+ def clear_backtrace_filters
100
+ HydraulicBrake.configuration.backtrace_filters.clear
101
+ end
102
+
103
+ def build_exception(opts = {})
104
+ backtrace = ["hydraulic_brake/test/helper.rb:132:in `build_exception'",
105
+ "hydraulic_brake/test/backtrace.rb:4:in `build_notice_data'",
106
+ "/var/lib/gems/1.8/gems/hydraulic_brake-2.4.5/rails/init.rb:2:in `send_exception'"]
107
+ opts = {:backtrace => backtrace}.merge(opts)
108
+ BacktracedException.new(opts)
109
+ end
110
+
111
+ def build_notice_data(exception = nil)
112
+ exception ||= build_exception
113
+ {
114
+ :api_key => 'abc123',
115
+ :error_class => exception.class.name,
116
+ :error_message => "#{exception.class.name}: #{exception.message}",
117
+ :backtrace => exception.backtrace,
118
+ :environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
119
+ :request => {
120
+ :params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
121
+ :rails_root => '/path/to/application',
122
+ :url => "http://test.host/users/1"
123
+ },
124
+ :session => {
125
+ :key => '123abc',
126
+ :data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
127
+ }
128
+ }
129
+ end
130
+
131
+ def assert_caught_and_sent
132
+ assert !HydraulicBrake.sender.collected.empty?
133
+ end
134
+
135
+ def assert_caught_and_not_sent
136
+ assert HydraulicBrake.sender.collected.empty?
137
+ end
138
+
139
+ def assert_array_starts_with(expected, actual)
140
+ assert_respond_to actual, :to_ary
141
+ array = actual.to_ary.reverse
142
+ expected.reverse.each_with_index do |value, i|
143
+ assert_equal value, array[i]
144
+ end
145
+ end
146
+
147
+ def assert_valid_node(document, xpath, content)
148
+ nodes = document.xpath(xpath)
149
+ assert nodes.any?{|node| node.content == content },
150
+ "Expected xpath #{xpath} to have content #{content}, " +
151
+ "but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
152
+ "Document:\n#{document.to_s}"
153
+ end
154
+
155
+ def assert_logged(expected)
156
+ assert_received(HydraulicBrake, :write_verbose_log) do |expect|
157
+ expect.with {|actual| actual =~ expected }
158
+ end
159
+ end
160
+
161
+ def assert_not_logged(expected)
162
+ assert_received(HydraulicBrake, :write_verbose_log) do |expect|
163
+ expect.with {|actual| actual =~ expected }.never
164
+ end
165
+ end
166
+
167
+
168
+ end
169
+
170
+ module DefinesConstants
171
+ def setup
172
+ @defined_constants = []
173
+ end
174
+
175
+ def teardown
176
+ @defined_constants.each do |constant|
177
+ Object.__send__(:remove_const, constant)
178
+ end
179
+ end
180
+
181
+ def define_constant(name, value)
182
+ Object.const_set(name, value)
183
+ @defined_constants << name
184
+ end
185
+ end
186
+
187
+ # Also stolen from AS 2.3.2
188
+ class AsArray
189
+ # Wraps the object in an Array unless it's an Array. Converts the
190
+ # object to an Array using #to_ary if it implements that.
191
+ def self.wrap(object)
192
+ case object
193
+ when nil
194
+ []
195
+ when self
196
+ object
197
+ else
198
+ if object.respond_to?(:to_ary)
199
+ object.to_ary
200
+ else
201
+ [object]
202
+ end
203
+ end
204
+ end
205
+
206
+ end
207
+
208
+ class CollectingSender
209
+ attr_reader :collected
210
+
211
+ def initialize
212
+ @collected = []
213
+ end
214
+
215
+ def send_to_airbrake(data)
216
+ @collected << data
217
+ end
218
+ end
219
+
220
+ class FakeLogger
221
+ def info(*args); end
222
+ def debug(*args); end
223
+ def warn(*args); end
224
+ def error(*args); end
225
+ def fatal(*args); end
226
+ end
227
+
228
+ class BacktracedException < Exception
229
+ attr_accessor :backtrace
230
+ def initialize(opts)
231
+ @backtrace = opts[:backtrace]
232
+ end
233
+ def set_backtrace(bt)
234
+ @backtrace = bt
235
+ end
236
+ def message
237
+ "Something went wrong. Did you press the red button?"
238
+ end
239
+ end