hydraulic_brake 0.0.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.
@@ -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