tartarus 1.0.3 → 2.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.
- data/.gitignore +1 -0
- data/.rvmrc +2 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +104 -0
- data/README.rdoc +30 -4
- data/Rakefile +10 -28
- data/{generators → lib/generators}/tartarus/USAGE +4 -3
- data/lib/generators/tartarus/tartarus_generator.rb +36 -0
- data/{generators → lib/generators}/tartarus/templates/app/controllers/exceptions_controller.rb +0 -0
- data/{generators → lib/generators}/tartarus/templates/app/models/logged_exception.rb +0 -0
- data/{generators → lib/generators}/tartarus/templates/app/views/exceptions/_exception.html.erb +0 -0
- data/{generators → lib/generators}/tartarus/templates/app/views/exceptions/details.html.erb +0 -0
- data/{generators → lib/generators}/tartarus/templates/app/views/exceptions/index.html.erb +0 -0
- data/{generators → lib/generators}/tartarus/templates/config/exceptions.yml +0 -0
- data/{generators → lib/generators}/tartarus/templates/db/migrate/add_logged_exceptions.rb +0 -0
- data/{generators → lib/generators}/tartarus/templates/public/javascripts/tartarus.jquery.js +0 -0
- data/{generators → lib/generators}/tartarus/templates/public/stylesheets/tartarus.css +0 -0
- data/{generators → lib/generators}/tartarus/templates/spec/controllers/exceptions_controller_spec.rb +1 -1
- data/{generators → lib/generators}/tartarus/templates/spec/models/logged_exception_spec.rb +0 -0
- data/lib/tartarus.rb +7 -3
- data/lib/tartarus/logger.rb +50 -14
- data/lib/tartarus/notifiers/mail.rb +25 -0
- data/lib/tartarus/rack.rb +23 -0
- data/lib/tartarus/railtie.rb +9 -0
- data/lib/tartarus/version.rb +3 -0
- data/spec/rails_app/.gitignore +4 -0
- data/spec/rails_app/.rspec +1 -0
- data/spec/rails_app/Gemfile +13 -0
- data/spec/rails_app/Gemfile.lock +99 -0
- data/spec/rails_app/README +256 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/controllers/logged_exceptions_controller.rb +31 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/{rails → rails_app}/app/models/logged_exception.rb +2 -1
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/app/views/logged_exceptions/_exception.html.erb +14 -0
- data/spec/rails_app/app/views/logged_exceptions/details.html.erb +86 -0
- data/spec/rails_app/app/views/logged_exceptions/index.html.erb +28 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +42 -0
- data/spec/rails_app/config/boot.rb +13 -0
- data/spec/rails_app/config/database.yml +22 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +26 -0
- data/spec/rails_app/config/environments/production.rb +49 -0
- data/spec/rails_app/config/environments/test.rb +35 -0
- data/spec/rails_app/config/exceptions.yml +18 -0
- data/spec/{rails → rails_app}/config/initializers/backtrace_silencers.rb +2 -2
- data/spec/{rails → rails_app}/config/initializers/inflections.rb +1 -1
- data/spec/{rails → rails_app}/config/initializers/mime_types.rb +0 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/{rails → rails_app}/config/locales/en.yml +1 -1
- data/spec/rails_app/config/routes.rb +58 -0
- data/spec/rails_app/db/migrate/20101230191040_add_logged_exception_table.rb +19 -0
- data/spec/rails_app/db/schema.rb +28 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/doc/README_FOR_APP +2 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +26 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/javascripts/application.js +2 -0
- data/spec/rails_app/public/javascripts/controls.js +965 -0
- data/spec/rails_app/public/javascripts/dragdrop.js +974 -0
- data/spec/rails_app/public/javascripts/effects.js +1123 -0
- data/spec/rails_app/public/javascripts/prototype.js +6001 -0
- data/spec/rails_app/public/javascripts/rails.js +175 -0
- data/spec/rails_app/public/javascripts/tartarus.jquery.js +8 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/public/stylesheets/tartarus.css +26 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/rails_app/spec/controllers/logged_exceptions_controller_spec.rb +83 -0
- data/spec/rails_app/spec/models/logged_exception_spec.rb +7 -0
- data/spec/rails_app/spec/spec_helper.rb +27 -0
- data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +14 -7
- data/spec/tartarus/logger_spec.rb +51 -23
- data/spec/tartarus_spec.rb +5 -8
- data/tartarus.gemspec +11 -103
- metadata +148 -94
- data/VERSION +0 -1
- data/generators/tartarus/tartarus_generator.rb +0 -50
- data/lib/tartarus/notifier.rb +0 -11
- data/lib/tartarus/rescue.rb +0 -39
- data/rails/init.rb +0 -3
- data/spec/rails/app/controllers/application_controller.rb +0 -10
- data/spec/rails/config/boot.rb +0 -110
- data/spec/rails/config/database.yml +0 -5
- data/spec/rails/config/environment.rb +0 -41
- data/spec/rails/config/environments/development.rb +0 -17
- data/spec/rails/config/environments/production.rb +0 -28
- data/spec/rails/config/environments/test.rb +0 -28
- data/spec/rails/config/exceptions.yml +0 -9
- data/spec/rails/config/initializers/new_rails_defaults.rb +0 -21
- data/spec/rails/config/initializers/session_store.rb +0 -15
- data/spec/rails/config/routes.rb +0 -43
- data/spec/rails/db/test.sqlite3 +0 -0
- data/spec/rcov.opts +0 -3
- data/spec/spec.opts +0 -4
- data/spec/tartarus/rescue_spec.rb +0 -86
- data/views/tartarus_notifier/notification.html.erb +0 -9
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
// Technique from Juriy Zaytsev
|
|
3
|
+
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
|
|
4
|
+
function isEventSupported(eventName) {
|
|
5
|
+
var el = document.createElement('div');
|
|
6
|
+
eventName = 'on' + eventName;
|
|
7
|
+
var isSupported = (eventName in el);
|
|
8
|
+
if (!isSupported) {
|
|
9
|
+
el.setAttribute(eventName, 'return;');
|
|
10
|
+
isSupported = typeof el[eventName] == 'function';
|
|
11
|
+
}
|
|
12
|
+
el = null;
|
|
13
|
+
return isSupported;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isForm(element) {
|
|
17
|
+
return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isInput(element) {
|
|
21
|
+
if (Object.isElement(element)) {
|
|
22
|
+
var name = element.nodeName.toUpperCase()
|
|
23
|
+
return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
|
|
24
|
+
}
|
|
25
|
+
else return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var submitBubbles = isEventSupported('submit'),
|
|
29
|
+
changeBubbles = isEventSupported('change')
|
|
30
|
+
|
|
31
|
+
if (!submitBubbles || !changeBubbles) {
|
|
32
|
+
// augment the Event.Handler class to observe custom events when needed
|
|
33
|
+
Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
|
|
34
|
+
function(init, element, eventName, selector, callback) {
|
|
35
|
+
init(element, eventName, selector, callback)
|
|
36
|
+
// is the handler being attached to an element that doesn't support this event?
|
|
37
|
+
if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
|
|
38
|
+
(!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
|
|
39
|
+
// "submit" => "emulated:submit"
|
|
40
|
+
this.eventName = 'emulated:' + this.eventName
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!submitBubbles) {
|
|
47
|
+
// discover forms on the page by observing focus events which always bubble
|
|
48
|
+
document.on('focusin', 'form', function(focusEvent, form) {
|
|
49
|
+
// special handler for the real "submit" event (one-time operation)
|
|
50
|
+
if (!form.retrieve('emulated:submit')) {
|
|
51
|
+
form.on('submit', function(submitEvent) {
|
|
52
|
+
var emulated = form.fire('emulated:submit', submitEvent, true)
|
|
53
|
+
// if custom event received preventDefault, cancel the real one too
|
|
54
|
+
if (emulated.returnValue === false) submitEvent.preventDefault()
|
|
55
|
+
})
|
|
56
|
+
form.store('emulated:submit', true)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!changeBubbles) {
|
|
62
|
+
// discover form inputs on the page
|
|
63
|
+
document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
|
|
64
|
+
// special handler for real "change" events
|
|
65
|
+
if (!input.retrieve('emulated:change')) {
|
|
66
|
+
input.on('change', function(changeEvent) {
|
|
67
|
+
input.fire('emulated:change', changeEvent, true)
|
|
68
|
+
})
|
|
69
|
+
input.store('emulated:change', true)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleRemote(element) {
|
|
75
|
+
var method, url, params;
|
|
76
|
+
|
|
77
|
+
var event = element.fire("ajax:before");
|
|
78
|
+
if (event.stopped) return false;
|
|
79
|
+
|
|
80
|
+
if (element.tagName.toLowerCase() === 'form') {
|
|
81
|
+
method = element.readAttribute('method') || 'post';
|
|
82
|
+
url = element.readAttribute('action');
|
|
83
|
+
params = element.serialize();
|
|
84
|
+
} else {
|
|
85
|
+
method = element.readAttribute('data-method') || 'get';
|
|
86
|
+
url = element.readAttribute('href');
|
|
87
|
+
params = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
new Ajax.Request(url, {
|
|
91
|
+
method: method,
|
|
92
|
+
parameters: params,
|
|
93
|
+
evalScripts: true,
|
|
94
|
+
|
|
95
|
+
onComplete: function(request) { element.fire("ajax:complete", request); },
|
|
96
|
+
onSuccess: function(request) { element.fire("ajax:success", request); },
|
|
97
|
+
onFailure: function(request) { element.fire("ajax:failure", request); }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
element.fire("ajax:after");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function handleMethod(element) {
|
|
104
|
+
var method = element.readAttribute('data-method'),
|
|
105
|
+
url = element.readAttribute('href'),
|
|
106
|
+
csrf_param = $$('meta[name=csrf-param]')[0],
|
|
107
|
+
csrf_token = $$('meta[name=csrf-token]')[0];
|
|
108
|
+
|
|
109
|
+
var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
|
|
110
|
+
element.parentNode.insert(form);
|
|
111
|
+
|
|
112
|
+
if (method !== 'post') {
|
|
113
|
+
var field = new Element('input', { type: 'hidden', name: '_method', value: method });
|
|
114
|
+
form.insert(field);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (csrf_param) {
|
|
118
|
+
var param = csrf_param.readAttribute('content'),
|
|
119
|
+
token = csrf_token.readAttribute('content'),
|
|
120
|
+
field = new Element('input', { type: 'hidden', name: param, value: token });
|
|
121
|
+
form.insert(field);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
form.submit();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
document.on("click", "*[data-confirm]", function(event, element) {
|
|
129
|
+
var message = element.readAttribute('data-confirm');
|
|
130
|
+
if (!confirm(message)) event.stop();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
document.on("click", "a[data-remote]", function(event, element) {
|
|
134
|
+
if (event.stopped) return;
|
|
135
|
+
handleRemote(element);
|
|
136
|
+
event.stop();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
document.on("click", "a[data-method]", function(event, element) {
|
|
140
|
+
if (event.stopped) return;
|
|
141
|
+
handleMethod(element);
|
|
142
|
+
event.stop();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
document.on("submit", function(event) {
|
|
146
|
+
var element = event.findElement(),
|
|
147
|
+
message = element.readAttribute('data-confirm');
|
|
148
|
+
if (message && !confirm(message)) {
|
|
149
|
+
event.stop();
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var inputs = element.select("input[type=submit][data-disable-with]");
|
|
154
|
+
inputs.each(function(input) {
|
|
155
|
+
input.disabled = true;
|
|
156
|
+
input.writeAttribute('data-original-value', input.value);
|
|
157
|
+
input.value = input.readAttribute('data-disable-with');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
var element = event.findElement("form[data-remote]");
|
|
161
|
+
if (element) {
|
|
162
|
+
handleRemote(element);
|
|
163
|
+
event.stop();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
document.on("ajax:after", "form", function(event, element) {
|
|
168
|
+
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
|
|
169
|
+
inputs.each(function(input) {
|
|
170
|
+
input.value = input.readAttribute('data-original-value');
|
|
171
|
+
input.removeAttribute('data-original-value');
|
|
172
|
+
input.disabled = false;
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
})();
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#tartarus { margin: 0px 20px }
|
|
2
|
+
|
|
3
|
+
#tartarus_cap { padding-bottom: 10px; border-bottom: 1px solid #777; margin: 20px 0px; }
|
|
4
|
+
#tartarus h2 { margin: 10px 0px; }
|
|
5
|
+
|
|
6
|
+
#tartarus_nav { float: right }
|
|
7
|
+
.tartarus_pagination { margin-top: 20px; }
|
|
8
|
+
|
|
9
|
+
#tartarus table { border-collapse: collapse; width: 100%; }
|
|
10
|
+
#tartarus table tr { border-bottom: 1px solid #E0DFE0; }
|
|
11
|
+
#tartarus table th, #tartarus table td { padding: 5px; }
|
|
12
|
+
#tartarus table th { text-align: left; }
|
|
13
|
+
|
|
14
|
+
#tartarus th#exception_location { width: 150px; }
|
|
15
|
+
#tartarus th#exception_date { width: 150px; }
|
|
16
|
+
#tartarus th#exception_count { text-align: center; }
|
|
17
|
+
|
|
18
|
+
#tartarus pre { -webkit-border-radius: 5px; -moz-border-radius: 5px; font-size: 10px; color: #fff; background-color: #222; padding: 10px; font-family: Consolas, Monaco, 'Courier New', Courier,monospace; }
|
|
19
|
+
#tartarus a, #tartarus a:visited { text-decoration: underline; #bdf; }
|
|
20
|
+
#tartarus a:hover { #09f }
|
|
21
|
+
|
|
22
|
+
#tartarus #exception { clear: both; }
|
|
23
|
+
#tartarus #exception_actions { float: right; }
|
|
24
|
+
|
|
25
|
+
#tartarus .toggle_data { display: none }
|
|
26
|
+
#tartarus #backtrace_information .toggle_data { display: block; }
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
|
3
|
+
|
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
|
6
|
+
require 'rails/commands'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
|
+
|
|
3
|
+
describe LoggedExceptionsController do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@exception = LoggedException.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe "#index" do
|
|
9
|
+
it 'should set an assigns of exceptions with the collection of all exception groups' do
|
|
10
|
+
LoggedException.should_receive(:all).with(:select => '*, COUNT(*) as count', :group => 'group_id', :order => 'created_at DESC').and_return([@exception])
|
|
11
|
+
|
|
12
|
+
get :index
|
|
13
|
+
assigns[:exceptions].should == [@exception]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#details" do
|
|
18
|
+
before(:each) do
|
|
19
|
+
@exception2 = LoggedException.new
|
|
20
|
+
LoggedException.stub!(:paginate).and_return([@exception, @exception2])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'should set an assigns of exceptions with a paginated collection' do
|
|
24
|
+
LoggedException.should_receive(:paginate).with(:all, :conditions => { :group_id => '89hasd98ashdasas98dhsda' },
|
|
25
|
+
:order => 'created_at DESC', :page => '1', :per_page => 1).and_return([@exception, @exception2])
|
|
26
|
+
|
|
27
|
+
get :details, :id => '89hasd98ashdasas98dhsda', :page => '1'
|
|
28
|
+
assigns[:exceptions].should == [@exception, @exception2]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'should set an assigns of exception with the first exception from the paginated collection' do
|
|
32
|
+
get :details, :id => '89hasd98ashdasas98dhsda'
|
|
33
|
+
assigns[:exception].should == @exception
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe "#remove_all" do
|
|
38
|
+
it 'should delete all exceptions' do
|
|
39
|
+
LoggedException.should_receive(:delete_all)
|
|
40
|
+
get :remove_all
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'should redirect to exceptions#index' do
|
|
44
|
+
get :remove_all
|
|
45
|
+
response.should redirect_to(:action => :index)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "#remove_group" do
|
|
50
|
+
it 'should delete all exceptions in a specific group' do
|
|
51
|
+
LoggedException.should_receive(:delete_all).with(:group_id => '892h39fds')
|
|
52
|
+
get :remove_group, :id => '892h39fds'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'should redirect to exceptions#index' do
|
|
56
|
+
get :remove_group, :id => '892h39fds'
|
|
57
|
+
response.should redirect_to(:action => :index)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "#remove_individual" do
|
|
62
|
+
before(:each) do
|
|
63
|
+
LoggedException.stub!(:find_by_id).and_return(@exception)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'should remove a single exception' do
|
|
67
|
+
@exception.should_receive(:destroy)
|
|
68
|
+
get :remove_individual, :id => 1
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'should redirect to exceptions#index if the exception group contains no more exceptions' do
|
|
72
|
+
LoggedException.stub!(:count).and_return(0)
|
|
73
|
+
get :remove_individual, :id => 1
|
|
74
|
+
response.should redirect_to(:action => :index)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'should redirect to exceptions#details if the exception group contains more exceptions' do
|
|
78
|
+
LoggedException.stub!(:count).and_return(1)
|
|
79
|
+
get :remove_individual, :id => 1
|
|
80
|
+
response.should redirect_to(:action => :details)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
3
|
+
require File.expand_path("../../config/environment", __FILE__)
|
|
4
|
+
require 'rspec/rails'
|
|
5
|
+
|
|
6
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
|
7
|
+
# in spec/support/ and its subdirectories.
|
|
8
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
# == Mock Framework
|
|
12
|
+
#
|
|
13
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
|
14
|
+
#
|
|
15
|
+
# config.mock_with :mocha
|
|
16
|
+
# config.mock_with :flexmock
|
|
17
|
+
# config.mock_with :rr
|
|
18
|
+
config.mock_with :rspec
|
|
19
|
+
|
|
20
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
|
21
|
+
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
|
22
|
+
|
|
23
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
|
24
|
+
# examples within a transaction, remove the following line or assign false
|
|
25
|
+
# instead of true.
|
|
26
|
+
config.use_transactional_fixtures = true
|
|
27
|
+
end
|
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/rails_app/config/environment", __FILE__)
|
|
4
|
+
require 'rspec/rails'
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require
|
|
6
|
-
require 'spec/rails'
|
|
6
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
|
7
|
+
# in spec/support/ and its subdirectories.
|
|
8
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
|
7
9
|
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
config.mock_with :rspec
|
|
12
|
+
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
|
13
|
+
config.use_transactional_fixtures = true
|
|
14
|
+
end
|
|
8
15
|
|
|
9
16
|
def fake_controller_request
|
|
10
17
|
stub('request',
|
|
@@ -17,10 +24,10 @@ def fake_controller_request
|
|
|
17
24
|
'rack.request.cookie_hash' => {}
|
|
18
25
|
},
|
|
19
26
|
:method => 'post',
|
|
20
|
-
:
|
|
27
|
+
:filtered_parameters => 'params',
|
|
21
28
|
:format => 'html',
|
|
22
29
|
:protocol => 'http://',
|
|
23
|
-
:
|
|
30
|
+
:fullpath => '/my/uri')
|
|
24
31
|
end
|
|
25
32
|
|
|
26
33
|
class LoggedException < ActiveRecord::Base
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
|
|
3
3
|
describe Tartarus::Logger do
|
|
4
|
-
it 'should serialize the request attribute' do
|
|
5
|
-
LoggedException.serialized_attributes.include?('request').should be_true
|
|
6
|
-
end
|
|
7
|
-
|
|
8
4
|
describe "#log" do
|
|
9
5
|
before(:each) do
|
|
6
|
+
Tartarus.stub(:configuration).and_return({ 'test' => { :enabled => true, "logger_class"=>"LoggedException" } })
|
|
10
7
|
LoggedException.stub!(:normalize_request_data).and_return({})
|
|
11
|
-
@controller = mock('controller', :controller_path => 'home', :
|
|
8
|
+
@controller = { 'action_controller.instance' => mock('controller', :controller_path => 'home', :action_name => 'index', :request => fake_controller_request) }
|
|
12
9
|
@exception = StandardError.new('An error has occured!')
|
|
13
10
|
@exception.stub!(:backtrace).and_return(['one', 'two', 'three'])
|
|
14
11
|
end
|
|
@@ -25,7 +22,7 @@ describe Tartarus::Logger do
|
|
|
25
22
|
end
|
|
26
23
|
|
|
27
24
|
it "should normalize the controller request data" do
|
|
28
|
-
|
|
25
|
+
LoggedException.should_receive(:normalize_request_data).with(@controller)
|
|
29
26
|
@logged_exception = LoggedException.log(@controller, @exception)
|
|
30
27
|
end
|
|
31
28
|
|
|
@@ -36,41 +33,72 @@ describe Tartarus::Logger do
|
|
|
36
33
|
end
|
|
37
34
|
|
|
38
35
|
it 'should return the group count' do
|
|
39
|
-
e = LoggedException.create( :group_id => "hash" )
|
|
36
|
+
e = LoggedException.create( :group_id => "hash", :request => {})
|
|
40
37
|
LoggedException.should_receive( :count ).with( :conditions => ["group_id = ?", 'hash'] ).and_return( 42 )
|
|
41
38
|
e.group_count.should == 42
|
|
42
39
|
end
|
|
43
40
|
|
|
44
41
|
describe '#handle_notifications' do
|
|
45
42
|
before(:each) do
|
|
46
|
-
@
|
|
47
|
-
Tartarus.configuration
|
|
48
|
-
Tartarus.configuration['notification_address'] = 'test@example.com'
|
|
43
|
+
@logged_exception = LoggedException.create(:request => {})
|
|
44
|
+
Tartarus.stub(:configuration).and_return({ 'notification_threshold' => 10, 'notification_address' => 'test@example.com', 'enabled' => true, "logger_class"=>"LoggedException" })
|
|
49
45
|
end
|
|
50
46
|
|
|
51
|
-
it 'should return and not deliver notification if there is no address present' do
|
|
52
|
-
Tartarus
|
|
53
|
-
Tartarus.
|
|
47
|
+
it 'should return and not deliver notification if there is no address present' do
|
|
48
|
+
Tartarus.should_receive(:configuration).and_return({ 'enabled' => true, "logger_class"=>"LoggedException" })
|
|
49
|
+
Tartarus::Notifiers::Mail.should_receive( :deliver_notification ).never
|
|
54
50
|
|
|
55
|
-
@
|
|
51
|
+
@logged_exception.handle_notifications
|
|
56
52
|
end
|
|
57
53
|
|
|
58
54
|
it 'should send email if there is an address present and the count matches the threshold' do
|
|
59
|
-
Tartarus::
|
|
60
|
-
@
|
|
61
|
-
@
|
|
55
|
+
Tartarus::Notifiers::Mail.should_receive( :deliver_notification ).with( 'test@example.com', @logged_exception )
|
|
56
|
+
@logged_exception.stub( :group_count ).and_return( 20 )
|
|
57
|
+
@logged_exception.handle_notifications
|
|
62
58
|
end
|
|
63
59
|
|
|
64
60
|
it 'should send email if there is an address present and it is the first exception in a group' do
|
|
65
|
-
Tartarus::
|
|
66
|
-
@
|
|
67
|
-
@
|
|
61
|
+
Tartarus::Notifiers::Mail.should_receive( :deliver_notification ).with( 'test@example.com', @logged_exception )
|
|
62
|
+
@logged_exception.stub( :group_count ).and_return( 1 )
|
|
63
|
+
@logged_exception.handle_notifications
|
|
68
64
|
end
|
|
69
65
|
|
|
70
66
|
it 'should not send email if there is an address present and the count does not match the threshold' do
|
|
71
|
-
Tartarus::
|
|
72
|
-
@
|
|
73
|
-
@
|
|
67
|
+
Tartarus::Notifiers::Mail.should_receive( :deliver_notification ).never
|
|
68
|
+
@logged_exception.stub( :group_count ).and_return( 22 )
|
|
69
|
+
@logged_exception.handle_notifications
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe 'when normalizing request data for tartarus' do
|
|
74
|
+
before(:each) do
|
|
75
|
+
@mock_env = { 'action_controller.instance' => stub('controller_instance', :request => fake_controller_request) }
|
|
76
|
+
@logged_exception = LoggedException.create(:request => {})
|
|
77
|
+
Tartarus.stub(:configuration).and_return({ 'notification_threshold' => 10, 'notification_address' => 'test@example.com', 'enabled' => true, "logger_class"=>"LoggedException" })
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'should have the session hash' do
|
|
81
|
+
params = LoggedException.normalize_request_data(@mock_env)
|
|
82
|
+
params[:session].should_not be_blank
|
|
83
|
+
params[:session].should be_an_instance_of(Hash)
|
|
84
|
+
params[:session].should == { :cookie => {}, :variables => { :id=>"123123" } }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'should have a enviroment hash that contains a hash of only the uppercase keys of the original controller request hash' do
|
|
88
|
+
params = LoggedException.normalize_request_data(@mock_env)
|
|
89
|
+
params[:enviroment].should_not be_blank
|
|
90
|
+
params[:enviroment].should == { "http_host" => "test_host", "loooooooong_key_two" => "key_two_value", "key_one" => "key_one_value", :server => `hostname -s`.chomp, :process => $$ }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'should have a http details hash' do
|
|
94
|
+
params = LoggedException.normalize_request_data(@mock_env)
|
|
95
|
+
params[:http_details].should_not be_blank
|
|
96
|
+
params[:http_details].should == { :parameters => "params", :format => "html", :method => "POST", :url => "http://test_host/my/uri" }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should return a hash of request data" do
|
|
100
|
+
params = LoggedException.normalize_request_data(@mock_env)
|
|
101
|
+
params.should be_an_instance_of(Hash)
|
|
74
102
|
end
|
|
75
103
|
end
|
|
76
104
|
|