radiant-exception_notification-extension 0.8.1
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/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
|