radiant-exception_notification-extension 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +68 -0
- data/Rakefile +120 -0
- data/app/models/exception_notifier.rb +35 -0
- data/app/models/internal_server_error_page.rb +25 -0
- data/app/views/exception_notifier/notification.html.erb +34 -0
- data/exception_notification_extension.rb +19 -0
- data/lib/exception_notification.rb +61 -0
- data/lib/exception_notification/page_extensions.rb +34 -0
- data/lib/radiant-exception_notification-extension.rb +4 -0
- data/lib/tasks/exception_notification_extension_tasks.rake +12 -0
- data/radiant-exception_notification-extension.gemspec +24 -0
- data/test/functional/exception_notification_test.rb +56 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/exception_notifier_page_test.rb +51 -0
- data/test/unit/exception_notifier_test.rb +32 -0
- metadata +85 -0
data/README
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
= EXCEPTION NOTIFICATION
|
2
|
+
|
3
|
+
Extends Radiant's error handling to include email notification and Radiant-
|
4
|
+
managed error templates for exceptions raised in other extensions. Based on
|
5
|
+
Jamis Buck's original Rails exception notifier.
|
6
|
+
|
7
|
+
= USAGE
|
8
|
+
|
9
|
+
1. Enable ActionMailer
|
10
|
+
|
11
|
+
Locate +config.frameworks -= [ :action_mailer ]+ in config/environment.rb.
|
12
|
+
Comment out this line, or remove action_mailer from the list of frameworks
|
13
|
+
you are skipping.
|
14
|
+
|
15
|
+
2. Define the email addresses ExceptionNotifier should use
|
16
|
+
|
17
|
+
Set the following somewhere within your environment:
|
18
|
+
|
19
|
+
ExceptionNotifier.email_to = 'send@to.email'
|
20
|
+
ExceptionNotifier.email_from = 'sent@from.email'
|
21
|
+
|
22
|
+
3. Create some error templates
|
23
|
+
|
24
|
+
Exception Notification adds an additional Page subclass called
|
25
|
+
InternalServerErrorPage. This and its existing sibling, FileNotFoundPage,
|
26
|
+
determine what gets rendered when an exception is raised. Create one of
|
27
|
+
each within your content tree. ExceptionNotification is aware of the
|
28
|
+
multi-site extension, so you can create individual error pages for
|
29
|
+
each site.
|
30
|
+
|
31
|
+
= NOTES
|
32
|
+
|
33
|
+
By default, your FileNotFound page will be rendered when the following
|
34
|
+
exceptions are caught:
|
35
|
+
|
36
|
+
* ActiveRecord::RecordNotFound
|
37
|
+
* ActionController::UnknownController
|
38
|
+
* ActionController::UnknownAction
|
39
|
+
* ActionController::RoutingError
|
40
|
+
|
41
|
+
All other errors will render with an InternalServerErrorPage. Both templates
|
42
|
+
are rendered even when running in development mode. If you'd like your stack
|
43
|
+
traces displayed (like dev mode in a standard Rails application,) set the
|
44
|
+
following somewhere within your environment:
|
45
|
+
|
46
|
+
Radiant::Config['debug?'] = true
|
47
|
+
|
48
|
+
==============================================================================
|
49
|
+
|
50
|
+
Copyright (c) 2008 Digital Pulp, Inc.
|
51
|
+
|
52
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
53
|
+
of this software and associated documentation files (the "Software"), to deal
|
54
|
+
in the Software without restriction, including without limitation the rights
|
55
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
56
|
+
copies of the Software, and to permit persons to whom the Software is
|
57
|
+
furnished to do so, subject to the following conditions:
|
58
|
+
|
59
|
+
The above copyright notice and this permission notice shall be included in
|
60
|
+
all copies or substantial portions of the Software.
|
61
|
+
|
62
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
63
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
64
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
65
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
66
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
67
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
68
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# I think this is the one that should be moved to the extension Rakefile template
|
2
|
+
|
3
|
+
# In rails 1.2, plugins aren't available in the path until they're loaded.
|
4
|
+
# Check to see if the rspec plugin is installed first and require
|
5
|
+
# it if it is. If not, use the gem version.
|
6
|
+
|
7
|
+
# Determine where the RSpec plugin is by loading the boot
|
8
|
+
unless defined? RADIANT_ROOT
|
9
|
+
ENV["RAILS_ENV"] = "test"
|
10
|
+
case
|
11
|
+
when ENV["RADIANT_ENV_FILE"]
|
12
|
+
require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
|
13
|
+
when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
|
14
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
|
15
|
+
else
|
16
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake'
|
21
|
+
require 'rake/rdoctask'
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
|
25
|
+
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
# require 'spec/translator'
|
28
|
+
|
29
|
+
# Cleanup the RADIANT_ROOT constant so specs will load the environment
|
30
|
+
Object.send(:remove_const, :RADIANT_ROOT)
|
31
|
+
|
32
|
+
extension_root = File.expand_path(File.dirname(__FILE__))
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
task :stats => "spec:statsetup"
|
36
|
+
|
37
|
+
desc "Run all specs in spec directory"
|
38
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
39
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
40
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
41
|
+
end
|
42
|
+
|
43
|
+
namespace :spec do
|
44
|
+
desc "Run all specs in spec directory with RCov"
|
45
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
46
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
47
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
48
|
+
t.rcov = true
|
49
|
+
t.rcov_opts = ['--exclude', 'spec', '--rails']
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Print Specdoc for all specs"
|
53
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
54
|
+
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
55
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
56
|
+
end
|
57
|
+
|
58
|
+
[:models, :controllers, :views, :helpers].each do |sub|
|
59
|
+
desc "Run the specs under spec/#{sub}"
|
60
|
+
Spec::Rake::SpecTask.new(sub) do |t|
|
61
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
62
|
+
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Hopefully no one has written their extensions in pre-0.9 style
|
67
|
+
# desc "Translate specs from pre-0.9 to 0.9 style"
|
68
|
+
# task :translate do
|
69
|
+
# translator = ::Spec::Translator.new
|
70
|
+
# dir = RAILS_ROOT + '/spec'
|
71
|
+
# translator.translate(dir, dir)
|
72
|
+
# end
|
73
|
+
|
74
|
+
# Setup specs for stats
|
75
|
+
task :statsetup do
|
76
|
+
require 'code_statistics'
|
77
|
+
::STATS_DIRECTORIES << %w(Model\ specs spec/models)
|
78
|
+
::STATS_DIRECTORIES << %w(View\ specs spec/views)
|
79
|
+
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
|
80
|
+
::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
|
81
|
+
::CodeStatistics::TEST_TYPES << "Model specs"
|
82
|
+
::CodeStatistics::TEST_TYPES << "View specs"
|
83
|
+
::CodeStatistics::TEST_TYPES << "Controller specs"
|
84
|
+
::CodeStatistics::TEST_TYPES << "Helper specs"
|
85
|
+
::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
|
86
|
+
end
|
87
|
+
|
88
|
+
namespace :db do
|
89
|
+
namespace :fixtures do
|
90
|
+
desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
|
91
|
+
task :load => :environment do
|
92
|
+
require 'active_record/fixtures'
|
93
|
+
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
|
94
|
+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
|
95
|
+
Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
desc 'Generate documentation for the exception_handler extension.'
|
103
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
104
|
+
rdoc.rdoc_dir = 'rdoc'
|
105
|
+
rdoc.title = 'ExceptionHandlerExtension'
|
106
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
107
|
+
rdoc.rdoc_files.include('README')
|
108
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
109
|
+
end
|
110
|
+
|
111
|
+
# For extensions that are in transition
|
112
|
+
desc 'Test the exception_handler extension.'
|
113
|
+
Rake::TestTask.new(:test) do |t|
|
114
|
+
t.libs << 'lib'
|
115
|
+
t.pattern = 'test/**/*_test.rb'
|
116
|
+
t.verbose = true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Load any custom rakefiles for extension
|
120
|
+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class ExceptionNotifier < ActionMailer::Base
|
5
|
+
|
6
|
+
cattr_accessor :email_from, :email_to
|
7
|
+
|
8
|
+
self.template_root = File.join(File.dirname(__FILE__),"..","views")
|
9
|
+
|
10
|
+
def notification(exception, controller, request)
|
11
|
+
time = Time.new
|
12
|
+
from ExceptionNotifier.email_from
|
13
|
+
recipients ExceptionNotifier.email_to
|
14
|
+
subject "Rails exception on #{request.env["HTTP_HOST"]} \@ #{time.to_s :db} » #{exception.class.name} occurred in #{controller.controller_name}\##{controller.action_name}"
|
15
|
+
body :exception => exception, :request => request,
|
16
|
+
:controller => controller, :host => request.env["HTTP_HOST"],
|
17
|
+
:backtrace => sanitize_backtrace(exception.backtrace),
|
18
|
+
:rails_root => rails_root, :time => time
|
19
|
+
|
20
|
+
content_type 'text/plain'
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
# cribbed from the original Rails exception_notification plugin: http://github.com/rails/exception_notification/tree/master
|
26
|
+
def sanitize_backtrace(trace)
|
27
|
+
re = Regexp.new(/^#{Regexp.escape(rails_root)}/)
|
28
|
+
trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s }
|
29
|
+
end
|
30
|
+
|
31
|
+
def rails_root
|
32
|
+
@rails_root ||= Pathname.new(RAILS_ROOT).cleanpath.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
class InternalServerErrorPage < Page
|
3
|
+
|
4
|
+
description %{
|
5
|
+
An "Internal Server Error" page can be used to override the default
|
6
|
+
error page in the event that a request raises an unhandled exception.
|
7
|
+
|
8
|
+
To create an "Internal Server Error" error page for an entire Web site,
|
9
|
+
create a page that is a child of the root page and assign it
|
10
|
+
"Internal Server Error" page type.
|
11
|
+
}
|
12
|
+
|
13
|
+
def virtual?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def headers
|
18
|
+
{ 'Status' => '500 Internal Server Error' }
|
19
|
+
end
|
20
|
+
|
21
|
+
def cache?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
An exception occurred:
|
2
|
+
|
3
|
+
EXCEPTION:
|
4
|
+
<%= @exception.class.name %> in <%= @controller.controller_name %>#<%= @controller.action_name %>
|
5
|
+
|
6
|
+
ERROR:
|
7
|
+
<%= @exception.message %>
|
8
|
+
|
9
|
+
----------------
|
10
|
+
Request Overview
|
11
|
+
----------------
|
12
|
+
* URL: <%= @request.protocol %><%= @host %><%= @request.request_uri %>
|
13
|
+
* Parameters: <%= @request.parameters.inspect %>
|
14
|
+
* Session ID: <%= @request.session.instance_variable_get(:@session_id).inspect %>
|
15
|
+
* Session Data: <%= PP.pp(@request.session.instance_variable_get(:@data),"").gsub(/\n/, "\n ").strip %>
|
16
|
+
|
17
|
+
* Server : <%= `hostname`.chomp %>
|
18
|
+
* Process: <%= $$ %>
|
19
|
+
* Rails root: <%= @rails_root %>
|
20
|
+
|
21
|
+
* Date/Time: <%= @time.to_s :full %>
|
22
|
+
|
23
|
+
---------------
|
24
|
+
Request Details
|
25
|
+
---------------
|
26
|
+
<% max = @request.env.keys.max { |a,b| a.length <=> b.length } -%>
|
27
|
+
<% @request.env.keys.sort.each do |key| -%>
|
28
|
+
* <%= "%-*s: %s" % [max.length, key, @request.env[key].to_s.strip] %>
|
29
|
+
<% end -%>
|
30
|
+
|
31
|
+
---------
|
32
|
+
Backtrace
|
33
|
+
---------
|
34
|
+
<%= @backtrace.join("\n") %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require_dependency 'application_controller'
|
3
|
+
require 'radiant-exception_notification-extension'
|
4
|
+
|
5
|
+
class ExceptionNotificationExtension < Radiant::Extension
|
6
|
+
version RadiantExceptionNotificationExtension::VERSION
|
7
|
+
description "Adds exception notification with Radiant-managed error pages"
|
8
|
+
url "http://github.com/digitalpulp"
|
9
|
+
|
10
|
+
def activate
|
11
|
+
ApplicationController.send :include, ExceptionNotification
|
12
|
+
Page.send(:include, ExceptionNotification::PageExtensions)
|
13
|
+
InternalServerErrorPage # instantiate class within Page.descendants
|
14
|
+
end
|
15
|
+
|
16
|
+
def deactivate
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module ExceptionNotification
|
3
|
+
|
4
|
+
ERROR_TYPES = {404 => FileNotFoundPage, 500 => InternalServerErrorPage}
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
alias_method_chain :rescue_action_in_public, :notification
|
9
|
+
alias_method_chain :rescue_action_locally, :template
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def rescue_action_in_public_with_notification(exception)
|
14
|
+
case exception
|
15
|
+
when ActiveRecord::RecordNotFound, ActionController::UnknownController, ActionController::UnknownAction, ActionController::RoutingError
|
16
|
+
status_404(request)
|
17
|
+
else
|
18
|
+
status_500(request)
|
19
|
+
ExceptionNotifier.deliver_notification(exception, self, request)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def rescue_action_locally_with_template(exception)
|
24
|
+
unless Radiant::Config['debug?']
|
25
|
+
case exception
|
26
|
+
when ActiveRecord::RecordNotFound, ActionController::UnknownController, ActionController::UnknownAction, ActionController::RoutingError
|
27
|
+
status_404(request)
|
28
|
+
else
|
29
|
+
status_500(request)
|
30
|
+
ExceptionNotifier.deliver_notification(exception, self, request)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
rescue_action_locally_without_template exception
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def status_404(request = generic_request)
|
40
|
+
headers["Status"] = "404 Not Found"
|
41
|
+
page = Page.find_error_page(404)
|
42
|
+
page.request = request
|
43
|
+
response.body = page.render
|
44
|
+
end
|
45
|
+
|
46
|
+
def status_500(request = generic_request)
|
47
|
+
headers["Status"] = "500 Internal Server Error"
|
48
|
+
if page = Page.find_error_page(500)
|
49
|
+
page.request = request
|
50
|
+
response.body = page.render
|
51
|
+
else
|
52
|
+
response.body = "500 Internal Server Error. An exception occured while processing your request. Additionally, a custom Radiant managed 500 page was not found."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def generic_request
|
57
|
+
g = ActionController::AbstractRequest.new
|
58
|
+
g.relative_url_root = "/"
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module ExceptionNotification
|
3
|
+
module PageExtensions
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_error_page(type)
|
10
|
+
return nil unless page_class = ExceptionNotification::ERROR_TYPES[type]
|
11
|
+
if self.class_name == page_class.name
|
12
|
+
return self
|
13
|
+
else
|
14
|
+
children.each do |child|
|
15
|
+
found = child.find_error_page(type)
|
16
|
+
return found if found
|
17
|
+
end
|
18
|
+
end
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def find_error_page(type)
|
24
|
+
root = find_by_parent_id(nil)
|
25
|
+
if respond_to?(:current_site) && current_site
|
26
|
+
root = current_site.homepage
|
27
|
+
end
|
28
|
+
raise Page::MissingRootPageError unless root
|
29
|
+
root.find_error_page(type)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'radiant-exception_notification-extension'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'radiant-exception_notification-extension'
|
7
|
+
s.version = RadiantExceptionNotificationExtension::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Josh French']
|
10
|
+
s.email = ['josh@vitamin-j.com']
|
11
|
+
s.homepage = 'http://github.com/digitalpulp'
|
12
|
+
s.summary = %q{Exception notification extension for Radiant CMS}
|
13
|
+
s.description = %q{Adds exception notification with Radiant-managed error pages}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.post_install_message = %{
|
21
|
+
Add this to your radiant project with:
|
22
|
+
config.gem 'radiant-exception-notification', :version => '#{RadiantExceptionNotificationExtension::VERSION}'
|
23
|
+
}
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
3
|
+
|
4
|
+
class ExceptionNotificationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@controller = SiteController.new
|
8
|
+
class << @controller
|
9
|
+
def rescue_action(e)
|
10
|
+
rescue_action_in_public(e)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
@request = ActionController::TestRequest.new
|
14
|
+
@response = ActionController::TestResponse.new
|
15
|
+
ActionController::Base.consider_all_requests_local = false
|
16
|
+
ExceptionNotifier.stubs(:deliver_notification)
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
ActionController::Base.consider_all_requests_local = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_module_inclusion
|
24
|
+
assert ApplicationController.included_modules.include?(ExceptionNotification)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_rescue_action_in_public_should_render_when_404
|
28
|
+
exception = ActiveRecord::RecordNotFound.new
|
29
|
+
ExceptionNotifier.expects(:deliver_notification).never
|
30
|
+
@controller.expects(:show_page).raises(exception)
|
31
|
+
Page.expects(:find_error_page).with(404).returns(mock(:render => '404 template', :request= => @request))
|
32
|
+
@response.expects(:body=).with('404 template')
|
33
|
+
get :show_page, :url => "/"
|
34
|
+
assert_response :missing
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_rescue_action_in_public_should_send_notification_when_500
|
38
|
+
exception = NoMethodError.new
|
39
|
+
@controller.expects(:show_page).raises(exception)
|
40
|
+
ExceptionNotifier.expects(:deliver_notification)
|
41
|
+
Page.expects(:find_error_page).with(500).returns(mock(:render => '500 template', :request= => @request))
|
42
|
+
@response.expects(:body=).with('500 template')
|
43
|
+
get :show_page, :url => "/"
|
44
|
+
assert_response :error
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_rendered_page_has_access_to_request
|
48
|
+
url = PagePart.new(:name => 'body', :content => '<r:url/>')
|
49
|
+
page = Page.new(:parts => [url], :slug => '/bogus-url')
|
50
|
+
@controller.expects(:show_page).raises(NoMethodError.new)
|
51
|
+
Page.stubs(:find_error_page).with(500).returns(page)
|
52
|
+
get :show_page
|
53
|
+
assert_match(/bogus-url/, @response.body)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mocha'
|
5
|
+
# Load the environment
|
6
|
+
unless defined? RADIANT_ROOT
|
7
|
+
ENV["RAILS_ENV"] = "test"
|
8
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
|
9
|
+
end
|
10
|
+
require "#{RADIANT_ROOT}/test/test_helper"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
3
|
+
|
4
|
+
class ExceptionNotifierPageTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
create_page(Page) do |root|
|
8
|
+
create_page(FileNotFoundPage, :parent_id => root.id) do |filenotfound|
|
9
|
+
create_page(InternalServerErrorPage, :parent_id => filenotfound.id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
### Class methods ###
|
15
|
+
|
16
|
+
def test_should_return_a_direct_descendent
|
17
|
+
assert_equal @file_not_found_page, Page.find_error_page(404)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_return_a_distant_descendent
|
21
|
+
assert_equal @internal_server_error_page, Page.find_error_page(500)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_return_nil_if_no_error_page_defined
|
25
|
+
assert_nil Page.find_error_page(501)
|
26
|
+
end
|
27
|
+
|
28
|
+
### Instance methods ###
|
29
|
+
|
30
|
+
def test_should_find_self
|
31
|
+
assert_equal @file_not_found_page, @file_not_found_page.find_error_page(404)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_should_find_child
|
35
|
+
assert_equal @internal_server_error_page, @file_not_found_page.find_error_page(500)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_return_nil_if_neither_self_nor_child
|
39
|
+
assert_nil @internal_server_error_page.find_error_page(404)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def create_page(klass,attrs={})
|
45
|
+
name = klass.name.underscore
|
46
|
+
attrs.merge!(:title => name, :slug => name, :breadcrumb => name)
|
47
|
+
page = instance_variable_set("@#{name}", klass.create(attrs))
|
48
|
+
yield page if block_given?
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
3
|
+
|
4
|
+
class DummyController < ApplicationController; end
|
5
|
+
|
6
|
+
class ExceptionNotifierTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
ActionMailer::Base.deliveries = []
|
10
|
+
ActionMailer::Base.delivery_method = :test
|
11
|
+
ActionMailer::Base.perform_deliveries = true
|
12
|
+
|
13
|
+
@request = ActionController::TestRequest.new
|
14
|
+
@request.request_uri = "/foo/bar/baz"
|
15
|
+
|
16
|
+
@exception = NoMethodError.new
|
17
|
+
|
18
|
+
ExceptionNotifier.email_from ||= 'from@digitalpulp.com'
|
19
|
+
ExceptionNotifier.email_to ||= 'to@digitalpulp.com'
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_notification
|
23
|
+
@exception.set_backtrace(caller)
|
24
|
+
response = ExceptionNotifier.create_notification(@exception, DummyController.new, @request)
|
25
|
+
|
26
|
+
assert_match %r{#{@exception.class.name}}, response.body
|
27
|
+
assert_match %r{#{@request.request_uri}}, response.body
|
28
|
+
|
29
|
+
assert_equal ExceptionNotifier.email_from, response.from.first
|
30
|
+
assert_equal ExceptionNotifier.email_to, response.to.first
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: radiant-exception_notification-extension
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 61
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 1
|
10
|
+
version: 0.8.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Josh French
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-11-10 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Adds exception notification with Radiant-managed error pages
|
23
|
+
email:
|
24
|
+
- josh@vitamin-j.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- README
|
33
|
+
- Rakefile
|
34
|
+
- app/models/exception_notifier.rb
|
35
|
+
- app/models/internal_server_error_page.rb
|
36
|
+
- app/views/exception_notifier/notification.html.erb
|
37
|
+
- exception_notification_extension.rb
|
38
|
+
- lib/exception_notification.rb
|
39
|
+
- lib/exception_notification/page_extensions.rb
|
40
|
+
- lib/radiant-exception_notification-extension.rb
|
41
|
+
- lib/tasks/exception_notification_extension_tasks.rake
|
42
|
+
- radiant-exception_notification-extension.gemspec
|
43
|
+
- test/functional/exception_notification_test.rb
|
44
|
+
- test/test_helper.rb
|
45
|
+
- test/unit/exception_notifier_page_test.rb
|
46
|
+
- test/unit/exception_notifier_test.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/digitalpulp
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message: "\n Add this to your radiant project with:\n config.gem 'radiant-exception-notification', :version => '0.8.1'\n "
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.4.2
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Exception notification extension for Radiant CMS
|
81
|
+
test_files:
|
82
|
+
- test/functional/exception_notification_test.rb
|
83
|
+
- test/test_helper.rb
|
84
|
+
- test/unit/exception_notifier_page_test.rb
|
85
|
+
- test/unit/exception_notifier_test.rb
|