airbrake_user_attributes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +5 -0
- data/README.md +11 -0
- data/Rakefile +16 -0
- data/airbrake_user_attributes.gemspec +27 -0
- data/lib/airbrake_overrides/notice.rb +85 -0
- data/lib/airbrake_overrides/rails/controller_methods.rb +31 -0
- data/lib/airbrake_user_attributes/version.rb +3 -0
- data/lib/airbrake_user_attributes.rb +3 -0
- data/test/airbrake_2_2.xsd +79 -0
- data/test/helper.rb +262 -0
- data/test/notice_test.rb +131 -0
- metadata +222 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Airbrake - User Attributes
|
2
|
+
=======================
|
3
|
+
|
4
|
+
Adds information about the current user to error reports.
|
5
|
+
This information can only be processed and displayed by
|
6
|
+
[Errbit, the open source error catcher](https://github.com/errbit/errbit).
|
7
|
+
|
8
|
+
This gem can be used as a replacement for the `airbrake` gem,
|
9
|
+
since it loads `airbrake` as a dependency.
|
10
|
+
|
11
|
+
Copyright (c) 2012 Cloudfuji
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler/gem_helper'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the airbrake_user_attributes gem.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
Bundler::GemHelper.install_tasks
|
16
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'airbrake_user_attributes/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'airbrake_user_attributes'
|
7
|
+
s.authors = ['Nathan Broadbent']
|
8
|
+
s.email = 'nathan.f77@gmail.com'
|
9
|
+
s.homepage = 'http://cloudfuji.com'
|
10
|
+
s.summary = 'Send Airbrake notifications with user attributes'
|
11
|
+
s.description = 'Adds information about the current user to error reports'
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.version = AirbrakeUserAttributes::VERSION
|
14
|
+
|
15
|
+
s.add_development_dependency("actionpack", "~> 2.3.8")
|
16
|
+
s.add_development_dependency("activerecord", "~> 2.3.8")
|
17
|
+
s.add_development_dependency("activesupport", "~> 2.3.8")
|
18
|
+
s.add_development_dependency("bourne", ">= 1.0")
|
19
|
+
s.add_development_dependency("fakeweb", "~> 1.3.0")
|
20
|
+
s.add_development_dependency("nokogiri", "~> 1.4.3.1")
|
21
|
+
s.add_development_dependency("rspec", "~> 2.6.0")
|
22
|
+
s.add_development_dependency("sham_rack", "~> 1.3.0")
|
23
|
+
s.add_development_dependency("shoulda", "~> 2.11.3")
|
24
|
+
|
25
|
+
s.add_dependency 'airbrake', '>= 3.0.9'
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'airbrake/notice'
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
class Notice
|
5
|
+
# User information
|
6
|
+
# - Provides information about the currently logged in user
|
7
|
+
attr_reader :user_attributes
|
8
|
+
|
9
|
+
def initialize_with_user_attributes(args)
|
10
|
+
self.user_attributes = args[:user_attributes] || {}
|
11
|
+
initialize_without_user_attributes(args)
|
12
|
+
end
|
13
|
+
alias_method_chain :initialize, :user_attributes
|
14
|
+
|
15
|
+
# Converts the given notice to XML
|
16
|
+
# Need to override whole builder to add user-attributes at end.
|
17
|
+
def to_xml
|
18
|
+
builder = Builder::XmlMarkup.new
|
19
|
+
builder.instruct!
|
20
|
+
xml = builder.notice(:version => Airbrake::API_VERSION) do |notice|
|
21
|
+
notice.tag!("api-key", api_key)
|
22
|
+
notice.notifier do |notifier|
|
23
|
+
notifier.name(notifier_name)
|
24
|
+
notifier.version(notifier_version)
|
25
|
+
notifier.url(notifier_url)
|
26
|
+
end
|
27
|
+
notice.error do |error|
|
28
|
+
error.tag!('class', error_class)
|
29
|
+
error.message(error_message)
|
30
|
+
error.backtrace do |backtrace|
|
31
|
+
self.backtrace.lines.each do |line|
|
32
|
+
backtrace.line(:number => line.number,
|
33
|
+
:file => line.file,
|
34
|
+
:method => line.method)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if url ||
|
39
|
+
controller ||
|
40
|
+
action ||
|
41
|
+
!parameters.blank? ||
|
42
|
+
!cgi_data.blank? ||
|
43
|
+
!session_data.blank?
|
44
|
+
notice.request do |request|
|
45
|
+
request.url(url)
|
46
|
+
request.component(controller)
|
47
|
+
request.action(action)
|
48
|
+
unless parameters.nil? || parameters.empty?
|
49
|
+
request.params do |params|
|
50
|
+
xml_vars_for(params, parameters)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
unless session_data.nil? || session_data.empty?
|
54
|
+
request.session do |session|
|
55
|
+
xml_vars_for(session, session_data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
unless cgi_data.nil? || cgi_data.empty?
|
59
|
+
request.tag!("cgi-data") do |cgi_datum|
|
60
|
+
xml_vars_for(cgi_datum, cgi_data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
notice.tag!("server-environment") do |env|
|
66
|
+
env.tag!("project-root", project_root)
|
67
|
+
env.tag!("environment-name", environment_name)
|
68
|
+
env.tag!("hostname", hostname)
|
69
|
+
end
|
70
|
+
|
71
|
+
if user_attributes.present?
|
72
|
+
notice.tag!("user-attributes") do |user|
|
73
|
+
xml_vars_for(user, user_attributes)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
xml.to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
attr_writer :user_attributes
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'airbrake/rails/controller_methods'
|
2
|
+
|
3
|
+
module Airbrake
|
4
|
+
module Rails
|
5
|
+
module ControllerMethods
|
6
|
+
|
7
|
+
def airbrake_request_data_with_user_attributes
|
8
|
+
data = airbrake_request_data_without_user_attributes
|
9
|
+
data[:user_attributes] = current_user_filtered_attributes if respond_to?(:current_user)
|
10
|
+
data
|
11
|
+
end
|
12
|
+
alias_method_chain :airbrake_request_data, :user_attributes
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# Returns filtered attributes for current user (removes auth-related fields)
|
17
|
+
def current_user_filtered_attributes
|
18
|
+
attributes = current_user.attributes.reject do |k, v|
|
19
|
+
/password|token|login|sign_in|per_page|_at$/ =~ k
|
20
|
+
end
|
21
|
+
# Try to include a URL for the user, if possible.
|
22
|
+
if url_method = [:user_url, :admin_user_url].detect {|m| respond_to?(m) }
|
23
|
+
attributes[:url] = send(url_method, current_user)
|
24
|
+
end
|
25
|
+
attributes
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,79 @@
|
|
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="user-attributes" type="varList" 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">
|
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:schema>
|
data/test/helper.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
5
|
+
|
6
|
+
require 'thread'
|
7
|
+
|
8
|
+
require "bundler/setup"
|
9
|
+
|
10
|
+
require 'shoulda'
|
11
|
+
require 'mocha'
|
12
|
+
|
13
|
+
require 'action_controller'
|
14
|
+
require 'action_controller/test_process'
|
15
|
+
require 'active_record'
|
16
|
+
require 'active_support'
|
17
|
+
require 'nokogiri'
|
18
|
+
require 'rack'
|
19
|
+
require 'bourne'
|
20
|
+
require 'sham_rack'
|
21
|
+
|
22
|
+
require "airbrake"
|
23
|
+
require "airbrake_user_attributes"
|
24
|
+
|
25
|
+
begin require 'redgreen'; rescue LoadError; end
|
26
|
+
|
27
|
+
module TestMethods
|
28
|
+
def rescue_action e
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_raise
|
33
|
+
raise "Airbrake"
|
34
|
+
end
|
35
|
+
|
36
|
+
def do_not_raise
|
37
|
+
render :text => "Success"
|
38
|
+
end
|
39
|
+
|
40
|
+
def do_raise_ignored
|
41
|
+
raise ActiveRecord::RecordNotFound.new("404")
|
42
|
+
end
|
43
|
+
|
44
|
+
def do_raise_not_ignored
|
45
|
+
raise ActiveRecord::StatementInvalid.new("Statement invalid")
|
46
|
+
end
|
47
|
+
|
48
|
+
def manual_notify
|
49
|
+
notify_airbrake(Exception.new)
|
50
|
+
render :text => "Success"
|
51
|
+
end
|
52
|
+
|
53
|
+
def manual_notify_ignored
|
54
|
+
notify_airbrake(ActiveRecord::RecordNotFound.new("404"))
|
55
|
+
render :text => "Success"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Test::Unit::TestCase
|
60
|
+
def request(action = nil, method = :get, user_agent = nil, params = {})
|
61
|
+
@request = ActionController::TestRequest.new
|
62
|
+
@request.action = action ? action.to_s : ""
|
63
|
+
|
64
|
+
if user_agent
|
65
|
+
if @request.respond_to?(:user_agent=)
|
66
|
+
@request.user_agent = user_agent
|
67
|
+
else
|
68
|
+
@request.env["HTTP_USER_AGENT"] = user_agent
|
69
|
+
end
|
70
|
+
end
|
71
|
+
@request.query_parameters = @request.query_parameters.merge(params)
|
72
|
+
@response = ActionController::TestResponse.new
|
73
|
+
@controller.process(@request, @response)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Borrowed from ActiveSupport 2.3.2
|
77
|
+
def assert_difference(expression, difference = 1, message = nil, &block)
|
78
|
+
b = block.send(:binding)
|
79
|
+
exps = Array.wrap(expression)
|
80
|
+
before = exps.map { |e| eval(e, b) }
|
81
|
+
|
82
|
+
yield
|
83
|
+
|
84
|
+
exps.each_with_index do |e, i|
|
85
|
+
error = "#{e.inspect} didn't change by #{difference}"
|
86
|
+
error = "#{message}.\n#{error}" if message
|
87
|
+
assert_equal(before[i] + difference, eval(e, b), error)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_no_difference(expression, message = nil, &block)
|
92
|
+
assert_difference expression, 0, message, &block
|
93
|
+
end
|
94
|
+
|
95
|
+
def stub_sender
|
96
|
+
stub('sender', :send_to_airbrake => nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
def stub_sender!
|
100
|
+
Airbrake.sender = stub_sender
|
101
|
+
end
|
102
|
+
|
103
|
+
def stub_notice
|
104
|
+
stub('notice', :to_xml => 'some yaml', :ignore? => false)
|
105
|
+
end
|
106
|
+
|
107
|
+
def stub_notice!
|
108
|
+
stub_notice.tap do |notice|
|
109
|
+
Airbrake::Notice.stubs(:new => notice)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_dummy
|
114
|
+
Airbrake::DummySender.new
|
115
|
+
end
|
116
|
+
|
117
|
+
def reset_config
|
118
|
+
Airbrake.configuration = nil
|
119
|
+
Airbrake.configure do |config|
|
120
|
+
config.api_key = 'abc123'
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def clear_backtrace_filters
|
125
|
+
Airbrake.configuration.backtrace_filters.clear
|
126
|
+
end
|
127
|
+
|
128
|
+
def build_exception(opts = {})
|
129
|
+
backtrace = ["airbrake/test/helper.rb:132:in `build_exception'",
|
130
|
+
"airbrake/test/backtrace.rb:4:in `build_notice_data'",
|
131
|
+
"/var/lib/gems/1.8/gems/airbrake-2.4.5/rails/init.rb:2:in `send_exception'"]
|
132
|
+
opts = {:backtrace => backtrace}.merge(opts)
|
133
|
+
BacktracedException.new(opts)
|
134
|
+
end
|
135
|
+
|
136
|
+
class BacktracedException < Exception
|
137
|
+
attr_accessor :backtrace
|
138
|
+
def initialize(opts)
|
139
|
+
@backtrace = opts[:backtrace]
|
140
|
+
end
|
141
|
+
def set_backtrace(bt)
|
142
|
+
@backtrace = bt
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def build_notice_data(exception = nil)
|
147
|
+
exception ||= build_exception
|
148
|
+
{
|
149
|
+
:api_key => 'abc123',
|
150
|
+
:error_class => exception.class.name,
|
151
|
+
:error_message => "#{exception.class.name}: #{exception.message}",
|
152
|
+
:backtrace => exception.backtrace,
|
153
|
+
:environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
|
154
|
+
:request => {
|
155
|
+
:params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
|
156
|
+
:rails_root => '/path/to/application',
|
157
|
+
:url => "http://test.host/users/1"
|
158
|
+
},
|
159
|
+
:session => {
|
160
|
+
:key => '123abc',
|
161
|
+
:data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def assert_caught_and_sent
|
167
|
+
assert !Airbrake.sender.collected.empty?
|
168
|
+
end
|
169
|
+
|
170
|
+
def assert_caught_and_not_sent
|
171
|
+
assert Airbrake.sender.collected.empty?
|
172
|
+
end
|
173
|
+
|
174
|
+
def assert_array_starts_with(expected, actual)
|
175
|
+
assert_respond_to actual, :to_ary
|
176
|
+
array = actual.to_ary.reverse
|
177
|
+
expected.reverse.each_with_index do |value, i|
|
178
|
+
assert_equal value, array[i]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def assert_valid_node(document, xpath, content)
|
183
|
+
nodes = document.xpath(xpath)
|
184
|
+
assert nodes.any?{|node| node.content == content },
|
185
|
+
"Expected xpath #{xpath} to have content #{content}, " +
|
186
|
+
"but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
|
187
|
+
"Document:\n#{document.to_s}"
|
188
|
+
end
|
189
|
+
|
190
|
+
def assert_logged(expected)
|
191
|
+
assert_received(Airbrake, :write_verbose_log) do |expect|
|
192
|
+
expect.with {|actual| actual =~ expected }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def assert_not_logged(expected)
|
197
|
+
assert_received(Airbrake, :write_verbose_log) do |expect|
|
198
|
+
expect.with {|actual| actual =~ expected }.never
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
module DefinesConstants
|
206
|
+
def setup
|
207
|
+
@defined_constants = []
|
208
|
+
end
|
209
|
+
|
210
|
+
def teardown
|
211
|
+
@defined_constants.each do |constant|
|
212
|
+
Object.__send__(:remove_const, constant)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def define_constant(name, value)
|
217
|
+
Object.const_set(name, value)
|
218
|
+
@defined_constants << name
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Also stolen from AS 2.3.2
|
223
|
+
class Array
|
224
|
+
# Wraps the object in an Array unless it's an Array. Converts the
|
225
|
+
# object to an Array using #to_ary if it implements that.
|
226
|
+
def self.wrap(object)
|
227
|
+
case object
|
228
|
+
when nil
|
229
|
+
[]
|
230
|
+
when self
|
231
|
+
object
|
232
|
+
else
|
233
|
+
if object.respond_to?(:to_ary)
|
234
|
+
object.to_ary
|
235
|
+
else
|
236
|
+
[object]
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
class CollectingSender
|
244
|
+
attr_reader :collected
|
245
|
+
|
246
|
+
def initialize
|
247
|
+
@collected = []
|
248
|
+
end
|
249
|
+
|
250
|
+
def send_to_airbrake(data)
|
251
|
+
@collected << data
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class FakeLogger
|
256
|
+
def info(*args); end
|
257
|
+
def debug(*args); end
|
258
|
+
def warn(*args); end
|
259
|
+
def error(*args); end
|
260
|
+
def fatal(*args); end
|
261
|
+
end
|
262
|
+
|
data/test/notice_test.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class NoticeTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include DefinesConstants
|
6
|
+
|
7
|
+
def configure
|
8
|
+
Airbrake::Configuration.new.tap do |config|
|
9
|
+
config.api_key = 'abc123def456'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_notice(args = {})
|
14
|
+
configuration = args.delete(:configuration) || configure
|
15
|
+
Airbrake::Notice.new(configuration.merge(args))
|
16
|
+
end
|
17
|
+
|
18
|
+
def stub_request(attrs = {})
|
19
|
+
stub('request', { :parameters => { 'one' => 'two' },
|
20
|
+
:protocol => 'http',
|
21
|
+
:host => 'some.host',
|
22
|
+
:request_uri => '/some/uri',
|
23
|
+
:session => { :to_hash => { 'a' => 'b' } },
|
24
|
+
:env => { 'three' => 'four' } }.update(attrs))
|
25
|
+
end
|
26
|
+
|
27
|
+
def hostname
|
28
|
+
`hostname`.chomp
|
29
|
+
end
|
30
|
+
|
31
|
+
def assert_valid_notice_document(document)
|
32
|
+
xsd_path = File.join(File.dirname(__FILE__), "airbrake_2_2.xsd")
|
33
|
+
schema = Nokogiri::XML::Schema.new(IO.read(xsd_path))
|
34
|
+
errors = schema.validate(document)
|
35
|
+
assert errors.empty?, errors.collect{|e| e.message }.join
|
36
|
+
end
|
37
|
+
|
38
|
+
context "a Notice turned into XML" do
|
39
|
+
setup do
|
40
|
+
Airbrake.configure do |config|
|
41
|
+
config.api_key = "1234567890"
|
42
|
+
end
|
43
|
+
|
44
|
+
@exception = build_exception
|
45
|
+
|
46
|
+
@notice = build_notice({
|
47
|
+
:notifier_name => 'a name',
|
48
|
+
:notifier_version => '1.2.3',
|
49
|
+
:notifier_url => 'http://some.url/path',
|
50
|
+
:exception => @exception,
|
51
|
+
:controller => "controller",
|
52
|
+
:action => "action",
|
53
|
+
:url => "http://url.com",
|
54
|
+
:parameters => { "paramskey" => "paramsvalue",
|
55
|
+
"nestparentkey" => { "nestkey" => "nestvalue" } },
|
56
|
+
:session_data => { "sessionkey" => "sessionvalue" },
|
57
|
+
:cgi_data => { "cgikey" => "cgivalue" },
|
58
|
+
:user_attributes => { "id" => 1234, "username" => "jsmith", "url" => "http://www.example.com/users/1234" },
|
59
|
+
:project_root => "RAILS_ROOT",
|
60
|
+
:environment_name => "RAILS_ENV"
|
61
|
+
})
|
62
|
+
|
63
|
+
@xml = @notice.to_xml
|
64
|
+
|
65
|
+
@document = Nokogiri::XML::Document.parse(@xml)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "validate against the XML schema" do
|
69
|
+
assert_valid_notice_document @document
|
70
|
+
end
|
71
|
+
|
72
|
+
should "serialize a Notice to XML when sent #to_xml" do
|
73
|
+
assert_valid_node(@document, "//api-key", @notice.api_key)
|
74
|
+
|
75
|
+
assert_valid_node(@document, "//notifier/name", @notice.notifier_name)
|
76
|
+
assert_valid_node(@document, "//notifier/version", @notice.notifier_version)
|
77
|
+
assert_valid_node(@document, "//notifier/url", @notice.notifier_url)
|
78
|
+
|
79
|
+
assert_valid_node(@document, "//error/class", @notice.error_class)
|
80
|
+
assert_valid_node(@document, "//error/message", @notice.error_message)
|
81
|
+
|
82
|
+
assert_valid_node(@document, "//error/backtrace/line/@number", @notice.backtrace.lines.first.number)
|
83
|
+
assert_valid_node(@document, "//error/backtrace/line/@file", @notice.backtrace.lines.first.file)
|
84
|
+
assert_valid_node(@document, "//error/backtrace/line/@method", @notice.backtrace.lines.first.method)
|
85
|
+
|
86
|
+
assert_valid_node(@document, "//request/url", @notice.url)
|
87
|
+
assert_valid_node(@document, "//request/component", @notice.controller)
|
88
|
+
assert_valid_node(@document, "//request/action", @notice.action)
|
89
|
+
|
90
|
+
assert_valid_node(@document, "//request/params/var/@key", "paramskey")
|
91
|
+
assert_valid_node(@document, "//request/params/var", "paramsvalue")
|
92
|
+
assert_valid_node(@document, "//request/params/var/@key", "nestparentkey")
|
93
|
+
assert_valid_node(@document, "//request/params/var/var/@key", "nestkey")
|
94
|
+
assert_valid_node(@document, "//request/params/var/var", "nestvalue")
|
95
|
+
assert_valid_node(@document, "//request/session/var/@key", "sessionkey")
|
96
|
+
assert_valid_node(@document, "//request/session/var", "sessionvalue")
|
97
|
+
assert_valid_node(@document, "//request/cgi-data/var/@key", "cgikey")
|
98
|
+
assert_valid_node(@document, "//request/cgi-data/var", "cgivalue")
|
99
|
+
|
100
|
+
assert_valid_node(@document, "//server-environment/project-root", "RAILS_ROOT")
|
101
|
+
assert_valid_node(@document, "//server-environment/environment-name", "RAILS_ENV")
|
102
|
+
assert_valid_node(@document, "//server-environment/hostname", hostname)
|
103
|
+
|
104
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "id")
|
105
|
+
assert_valid_node(@document, "//user-attributes/var", "1234")
|
106
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "username")
|
107
|
+
assert_valid_node(@document, "//user-attributes/var", "jsmith")
|
108
|
+
assert_valid_node(@document, "//user-attributes/var/@key", "url")
|
109
|
+
assert_valid_node(@document, "//user-attributes/var", "http://www.example.com/users/1234")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
should "not send empty request data" do
|
114
|
+
notice = build_notice
|
115
|
+
assert_nil notice.url
|
116
|
+
assert_nil notice.controller
|
117
|
+
assert_nil notice.action
|
118
|
+
assert_empty notice.user_attributes
|
119
|
+
|
120
|
+
xml = notice.to_xml
|
121
|
+
document = Nokogiri::XML.parse(xml)
|
122
|
+
assert_nil document.at('//request/url')
|
123
|
+
assert_nil document.at('//request/component')
|
124
|
+
assert_nil document.at('//request/action')
|
125
|
+
assert_nil document.at('//user-attributes')
|
126
|
+
|
127
|
+
assert_valid_notice_document document
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: airbrake_user_attributes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Broadbent
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: actionpack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.3.8
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.3.8
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activerecord
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.3.8
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.3.8
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activesupport
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.3.8
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.8
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bourne
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: fakeweb
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.3.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: nokogiri
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.4.3.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.4.3.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.6.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 2.6.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: sham_rack
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.3.0
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.3.0
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: shoulda
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 2.11.3
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 2.11.3
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: airbrake
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 3.0.9
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 3.0.9
|
174
|
+
description: Adds information about the current user to error reports
|
175
|
+
email: nathan.f77@gmail.com
|
176
|
+
executables: []
|
177
|
+
extensions: []
|
178
|
+
extra_rdoc_files: []
|
179
|
+
files:
|
180
|
+
- .gitignore
|
181
|
+
- Gemfile
|
182
|
+
- README.md
|
183
|
+
- Rakefile
|
184
|
+
- airbrake_user_attributes.gemspec
|
185
|
+
- lib/airbrake_overrides/notice.rb
|
186
|
+
- lib/airbrake_overrides/rails/controller_methods.rb
|
187
|
+
- lib/airbrake_user_attributes.rb
|
188
|
+
- lib/airbrake_user_attributes/version.rb
|
189
|
+
- test/airbrake_2_2.xsd
|
190
|
+
- test/helper.rb
|
191
|
+
- test/notice_test.rb
|
192
|
+
homepage: http://cloudfuji.com
|
193
|
+
licenses: []
|
194
|
+
post_install_message:
|
195
|
+
rdoc_options: []
|
196
|
+
require_paths:
|
197
|
+
- lib
|
198
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
+
none: false
|
200
|
+
requirements:
|
201
|
+
- - ! '>='
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
segments:
|
205
|
+
- 0
|
206
|
+
hash: 311172291318117201
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
+
none: false
|
209
|
+
requirements:
|
210
|
+
- - ! '>='
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
segments:
|
214
|
+
- 0
|
215
|
+
hash: 311172291318117201
|
216
|
+
requirements: []
|
217
|
+
rubyforge_project:
|
218
|
+
rubygems_version: 1.8.24
|
219
|
+
signing_key:
|
220
|
+
specification_version: 3
|
221
|
+
summary: Send Airbrake notifications with user attributes
|
222
|
+
test_files: []
|