exception_handling 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 455910720fe5a8b91de548665df5c639c97dcf22
4
- data.tar.gz: 866669be2cb461553af17b502307e19a1af3b880
3
+ metadata.gz: 07258fd3838c1f4ad88afcc407b5a48c515cc1bb
4
+ data.tar.gz: 6bc4a796d301b5739a71b6436a9a3c348f03f2f3
5
5
  SHA512:
6
- metadata.gz: c9d3e9e02a983357bbec9211b096a6904447b1669ef12db296b1d9a277394b7d713e9fab8fa0fa9f21e4603c18e16a1b71b20fce64b7cf4335ba46fd0e7e19fe
7
- data.tar.gz: e0cc1d06e1aa28ffe22b9add5ef2c0ce4dd48fa9fa7d9894460cd50a756b4661c48a3a1ab2a6bd09a9c118250e87f8cbfc9f72dd1b98ff7e01b8a226acbdfc7c
6
+ metadata.gz: 866f948f04a3ac4c2abf81d221c148a6c236692242dbc318743344dc4f8bc5fb14b39ece122895438ba4c7e48305baef130a489c1b5d712399822b9ff5bad448
7
+ data.tar.gz: 82e94f9f3eb8030a852a93f341cc7b7694070267edc3773fa74aa3e7e3ac66fbe145a5be242816b20202912016836ebfef6898ea31433b02295920c6e2c35f90
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- exception_handling (1.0.3)
4
+ exception_handling (1.0.4)
5
5
  actionmailer (~> 3.2)
6
6
  actionpack (~> 3.2)
7
7
  activesupport (~> 3.2)
@@ -1,4 +1,9 @@
1
1
  --- !map:HashWithIndifferentAccess
2
+ Test BS:
3
+ error: "Some BS"
4
+ send_email: true
5
+ notes: "this is used by a test"
6
+
2
7
  All script kiddies:
3
8
  error: "ScriptKiddie suspected because of HTTP request without a referer"
4
9
 
@@ -0,0 +1,40 @@
1
+ module ExceptionHandling
2
+ class ExceptionCatalog
3
+
4
+ def initialize(filter_path)
5
+ @filter_path = filter_path
6
+ @filters = { }
7
+ @filters_last_modified_time = nil
8
+ end
9
+
10
+ def find(exception_data)
11
+ refresh_filters
12
+ @filters.values.find { |filter| filter.match?(exception_data) }
13
+ end
14
+
15
+ private
16
+
17
+ def refresh_filters
18
+ mtime = last_modified_time
19
+ if @filters_last_modified_time.nil? || mtime != @filters_last_modified_time
20
+ ExceptionHandling.logger.info("Reloading filter list from: #{@filter_path}. Last loaded time: #{@filters_last_modified_time}. Last modified time: #{mtime}")
21
+ load_file
22
+ end
23
+
24
+ rescue => ex # any exceptions
25
+ ExceptionHandling::log_error(ex, "ExceptionRegexes::refresh_filters: #{@filter_path}", nil, true)
26
+ end
27
+
28
+ def load_file
29
+ @filters_last_modified_time = last_modified_time # make race condition fall on the side of reloading unnecessarily next time rather than missing a set of changes
30
+
31
+ filters = YAML::load_file(@filter_path)
32
+ filter_hash_values = filters.map { |filter_name, regexes| [filter_name.to_sym, ExceptionDescription.new(filter_name.to_sym, regexes.symbolize_keys)] }
33
+ @filters = Hash[ filter_hash_values ]
34
+ end
35
+
36
+ def last_modified_time
37
+ File.mtime(@filter_path)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ module ExceptionHandling
2
+ class ExceptionDescription
3
+ MATCH_SECTIONS = [:error, :request, :session, :environment, :backtrace, :event_response]
4
+
5
+ CONFIGURATION_SECTIONS = {
6
+ send_email: false, # should email be sent?
7
+ send_metric: true, # should the metric be sent.
8
+ metric_name: nil, # Will be derived from section name if not passed
9
+ notes: nil # Will be included in exception email if set, used to keep notes and relevant links
10
+ }
11
+
12
+ attr_reader :filter_name, :send_email, :send_metric, :metric_name, :notes
13
+
14
+ def initialize(filter_name, configuration)
15
+ @filter_name = filter_name
16
+
17
+ invalid_sections = configuration.except(*(CONFIGURATION_SECTIONS.keys + MATCH_SECTIONS))
18
+ invalid_sections.empty? or raise ArgumentError, "Unknown section: #{invalid_sections.keys.join(",")}"
19
+
20
+ @configuration = CONFIGURATION_SECTIONS.merge(configuration)
21
+ @send_email = @configuration[:send_email]
22
+ @send_metric = @configuration[:send_metric]
23
+ @metric_name = (@configuration[:metric_name] || @filter_name ).to_s.gsub(" ","_")
24
+ @notes = @configuration[:notes]
25
+
26
+ regex_config = @configuration.reject { |k,v| k.in?(CONFIGURATION_SECTIONS.keys) || v.blank? }
27
+
28
+ @regexes = Hash[regex_config.map { |section, regex| [section, Regexp.new(regex, 'i') ] }]
29
+
30
+ !@regexes.empty? or raise ArgumentError, "Filter #{filter_name} has all blank regexes: #{configuration.inspect}"
31
+ end
32
+
33
+ def exception_data
34
+ {
35
+ "send_metric" => send_metric,
36
+ "metric_name" => metric_name,
37
+ "notes" => notes
38
+ }
39
+ end
40
+
41
+ def match?(exception_data)
42
+ @regexes.all? do |section, regex|
43
+ case target = exception_data[section.to_s] || exception_data[section]
44
+ when String
45
+ regex =~ target
46
+ when Array
47
+ target.any? { |row| row =~ regex }
48
+ when Hash
49
+ target[:to_s] =~ regex
50
+ when NilClass
51
+ false
52
+ else
53
+ raise "Unexpected class #{exception_data[section].class.name}"
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,3 +1,3 @@
1
1
  module ExceptionHandling
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  end
@@ -7,6 +7,8 @@ require 'invoca/utils'
7
7
  require "exception_handling/mailer"
8
8
  require "exception_handling/methods"
9
9
  require "exception_handling/log_stub_error"
10
+ require "exception_handling/exception_description"
11
+ require "exception_handling/exception_catalog"
10
12
 
11
13
  _ = ActiveSupport::HashWithIndifferentAccess
12
14
 
@@ -351,22 +353,18 @@ EOF
351
353
 
352
354
  SECTIONS.each { |section| add_to_s( data[section] ) if data[section].is_a? Hash }
353
355
 
354
- if exception_filters.filtered?( data )
355
- return
356
- end
357
-
358
- if summarize_exception( data ) == :Summarized
359
- return
360
- end
356
+ exception_description = exception_catalog.find( data )
357
+ merged_data = exception_description ? ActiveSupport::HashWithIndifferentAccess.new(exception_description.exception_data.merge(data)) : data
361
358
 
362
- deliver(ExceptionHandling::Mailer.exception_notification(data))
363
-
364
- if defined?(Errplane)
365
- Errplane.transmit(exc, :custom_data => data) unless exc.is_a?(Warning)
359
+ if exception_description && !exception_description.send_email
360
+ ExceptionHandling.logger.warn( "Filtered exception using '#{exception_description.filter_name}'; not sending email to notify" )
361
+ else
362
+ if summarize_exception( merged_data ) != :Summarized
363
+ deliver(ExceptionHandling::Mailer.exception_notification(merged_data))
364
+ end
366
365
  end
367
366
 
368
- execute_custom_log_error_callback(data, exc)
369
-
367
+ execute_custom_log_error_callback(merged_data, exc)
370
368
  nil
371
369
  end
372
370
 
@@ -470,8 +468,8 @@ EOF
470
468
  end.compact ]
471
469
  end
472
470
 
473
- def exception_filters
474
- @exception_filters ||= ExceptionFilters.new( ExceptionHandling.filter_list_filename )
471
+ def exception_catalog
472
+ @exception_catalog ||= ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
475
473
  end
476
474
 
477
475
  def clean_backtrace(exception)
@@ -594,81 +592,4 @@ EOF
594
592
  result
595
593
  end
596
594
  end
597
-
598
- class ExceptionFilters
599
- class Filter
600
- def initialize filter_name, regexes
601
- @regexes = Hash[ regexes.map do |section, regex|
602
- section = section.to_sym
603
- raise "Unknown section: #{section}" unless section == :error || section.in?( ExceptionHandling::SECTIONS )
604
- [section, (Regexp.new(regex, 'i') unless regex.blank?)]
605
- end ]
606
-
607
- raise "Filter #{filter_name} has all blank regexes: #{regexes.inspect}" if @regexes.all? { |section, regex| regex.nil? }
608
- end
609
-
610
- def match?(exception_data)
611
- @regexes.all? do |section, regex|
612
- regex.nil? ||
613
- case exception_data[section.to_s]
614
- when String
615
- regex =~ exception_data[section]
616
- when Array
617
- exception_data[section].any? { |row| row =~ regex }
618
- when Hash
619
- exception_data[section] && exception_data[section][:to_s] =~ regex
620
- when NilClass
621
- false
622
- else
623
- raise "Unexpected class #{exception_data[section].class.name}"
624
- end
625
- end
626
- end
627
- end
628
-
629
- def initialize( filter_path )
630
- @filter_path = filter_path
631
- @filters = { }
632
- @filters_last_modified_time = nil
633
- end
634
-
635
- def filtered?( exception_data )
636
- refresh_filters
637
-
638
- @filters.any? do |name, filter|
639
- if ( match = filter.match?( exception_data ) )
640
- ExceptionHandling.logger.warn( "Filtered exception using '#{name}'; not sending email to notify" )
641
- end
642
- match
643
- end
644
- end
645
-
646
- private
647
-
648
- def refresh_filters
649
- mtime = last_modified_time
650
- if @filters_last_modified_time.nil? || mtime != @filters_last_modified_time
651
- ExceptionHandling.logger.info( "Reloading filter list from: #{@filter_path}. Last loaded time: #{@filters_last_modified_time}. Last modified time: #{mtime}" )
652
- @filters_last_modified_time = mtime # make race condition fall on the side of reloading unnecessarily next time rather than missing a set of changes
653
-
654
- @filters = load_file
655
- end
656
-
657
- rescue => ex # any exceptions
658
- ExceptionHandling::log_error( ex, "ExceptionRegexes::refresh_filters: #{@filter_path}", nil, true)
659
- end
660
-
661
- def load_file
662
- # store all strings from YAML file into regex's on initial load, instead of converting to regex on every exception that is logged
663
- filters = YAML::load_file( @filter_path )
664
- Hash[ filters.map do |filter_name, regexes|
665
- [filter_name, Filter.new( filter_name, regexes )]
666
- end ]
667
- end
668
-
669
- def last_modified_time
670
- File.mtime( @filter_path )
671
- end
672
-
673
- end
674
595
  end
@@ -0,0 +1,65 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module ExceptionHandling
4
+ class ExceptionCatalogTest < ActiveSupport::TestCase
5
+
6
+ context "With stubbed yaml content" do
7
+ setup do
8
+ filter_list = { :exception1 => { error: "my error message" },
9
+ :exception2 => { error: "some other message", session: "misc data" } }
10
+ stub(YAML).load_file { filter_list }
11
+
12
+ # bump modified time up to get the above filter loaded
13
+ stub(File).mtime { incrementing_mtime }
14
+ end
15
+
16
+ context "with loaded data" do
17
+ setup do
18
+ stub(File).mtime { incrementing_mtime }
19
+ @exception_catalog = ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
20
+ @exception_catalog.send :load_file
21
+ end
22
+
23
+ should "have loaded filters" do
24
+ assert_equal 2, @exception_catalog.instance_eval("@filters").size
25
+ end
26
+
27
+ should "find messages in the catalog" do
28
+ assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
29
+ end
30
+
31
+ should "find matching data" do
32
+ exception_description = @exception_catalog.find(error: "this is my error message, which should match something")
33
+ assert exception_description
34
+ assert_equal :exception1, exception_description.filter_name
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ context "with live yaml content" do
41
+ setup do
42
+ @filename = File.expand_path('../../../../config/exception_filters.yml', __FILE__)
43
+ @exception_catalog = ExceptionCatalog.new( @filename )
44
+ assert_nothing_raised "Loading the exception filter should not raise" do
45
+ @exception_catalog.send :load_file
46
+ end
47
+ end
48
+
49
+ should "load the filter data" do
50
+ assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
51
+ assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
52
+ end
53
+
54
+
55
+ end
56
+
57
+ private
58
+
59
+ def incrementing_mtime
60
+ @mtime ||= Time.now
61
+ @mtime += 1.day
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module ExceptionHandling
4
+ class ExceptionDescriptionTest < ActiveSupport::TestCase
5
+
6
+ context "Filter" do
7
+
8
+ should "allow direct matching of strings" do
9
+ @f = ExceptionDescription.new(:filter1, :error => "my error message" )
10
+ assert @f.match?( 'error' => "my error message")
11
+ end
12
+
13
+ should "allow direct matching of strings on with symbol keys" do
14
+ @f = ExceptionDescription.new(:filter1, :error => "my error message" )
15
+ assert @f.match?( :error => "my error message")
16
+ end
17
+
18
+ should "complain when no regexps have a value" do
19
+ assert_raise(ArgumentError, "has all blank regexe") { ExceptionDescription.new(:filter1, error: nil) }
20
+ end
21
+
22
+ should "report when an invalid key is passed" do
23
+ assert_raise(ArgumentError, "Unknown section: not_a_parameter") { ExceptionDescription.new(:filter1, error: "my error message", not_a_parameter: false) }
24
+ end
25
+
26
+ should "allow send email to be specified" do
27
+ assert !ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).send_email
28
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_email
29
+ assert !ExceptionDescription.new(:filter1, error: "my error message" ).send_email
30
+ end
31
+
32
+ should "allow send_metric to be configured" do
33
+ assert !ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).send_metric
34
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_metric
35
+ assert ExceptionDescription.new(:filter1, error: "my error message" ).send_metric
36
+ end
37
+
38
+ should "provide metric name" do
39
+ assert_equal "filter1", ExceptionDescription.new(:filter1, error: "my error message" ).metric_name
40
+ assert_equal "some_other_metric_name", ExceptionDescription.new(:filter1, error: "my error message", metric_name: :some_other_metric_name ).metric_name
41
+ end
42
+
43
+ should "replace spaces in metric name" do
44
+ @f = ExceptionDescription.new(:"filter has spaces", :error => "my error message" )
45
+ assert_equal "filter_has_spaces", @f.metric_name
46
+ end
47
+
48
+ should "allow notes to be recorded" do
49
+ assert_equal nil, ExceptionDescription.new(:filter1, error: "my error message" ).notes
50
+ assert_equal "a long string", ExceptionDescription.new(:filter1, error: "my error message", notes: "a long string" ).notes
51
+ end
52
+
53
+ should "not consider config options in the filter set" do
54
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).match?( :error => "my error message")
55
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).match?( :error => "my error message")
56
+ assert ExceptionDescription.new(:filter1, error: "my error message", metric_name: "false" ).match?( :error => "my error message")
57
+ assert ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" ).match?( :error => "my error message")
58
+ end
59
+
60
+ should "provide exception details" do
61
+ exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" )
62
+
63
+ expected = {"send_metric" => true, "metric_name" => "filter1", "notes" => "hey"}
64
+
65
+ assert_equal expected, exception_description.exception_data
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -48,7 +48,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
48
48
  end
49
49
 
50
50
  context "configuration" do
51
- def append_organization_info(data)
51
+ def append_organization_info_config(data)
52
52
  begin
53
53
  data[:user_details] = {}
54
54
  data[:user_details][:username] = "CaryP"
@@ -58,7 +58,8 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
58
58
  end
59
59
  end
60
60
 
61
- def log_error_callback(data, ex)
61
+ def log_error_callback_config(data, ex)
62
+ @callback_data = data
62
63
  @fail_count += 1
63
64
  end
64
65
 
@@ -71,17 +72,23 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
71
72
  end
72
73
 
73
74
  should "support a custom_data_hook" do
74
- ExceptionHandling.custom_data_hook = method(:append_organization_info)
75
+ ExceptionHandling.custom_data_hook = method(:append_organization_info_config)
75
76
  ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
76
77
  assert_match(/Invoca Engineering Dept./, ActionMailer::Base.deliveries[-1].body.to_s)
77
78
  ExceptionHandling.custom_data_hook = nil
78
79
  end
79
80
 
80
- should "support a log_error hook" do
81
- ExceptionHandling.post_log_error_hook = method(:log_error_callback)
82
- ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
83
- assert_equal 1, @fail_count
84
- ExceptionHandling.post_log_error_hook = nil
81
+ should "support a log_error hook and pass exception data to it" do
82
+ begin
83
+ ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
84
+ ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
85
+ assert_equal 1, @fail_count
86
+ ensure
87
+ ExceptionHandling.post_log_error_hook = nil
88
+ end
89
+
90
+ assert_equal "this is used by a test", @callback_data["notes"]
91
+ assert_match(/this is used by a test/, ActionMailer::Base.deliveries[-1].body.to_s)
85
92
  end
86
93
 
87
94
  should "support rescue exceptions from a log_error hook" do
@@ -90,6 +97,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
90
97
  assert_equal 0, @fail_count
91
98
  ExceptionHandling.post_log_error_hook = nil
92
99
  end
100
+
93
101
  end
94
102
 
95
103
  context "Exception Handling" do
@@ -98,18 +106,6 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
98
106
  ExceptionHandling.send(:clear_exception_summary)
99
107
  end
100
108
 
101
- context "exception filter parsing and loading" do
102
- should "happen without an error" do
103
- stub(File).mtime { incrementing_mtime }
104
- exception_filters = ExceptionHandling.send( :exception_filters )
105
- assert( exception_filters.is_a?( ExceptionHandling::ExceptionFilters ) )
106
- assert_nothing_raised "Loading the exception filter should not raise" do
107
- exception_filters.send :load_file
108
- end
109
- assert !exception_filters.filtered?( "Scott says unlikely to ever match" )
110
- end
111
- end
112
-
113
109
  context "ExceptionHandling.ensure_safe" do
114
110
  should "log an exception if an exception is raised." do
115
111
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/)
@@ -232,6 +228,11 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
232
228
  Time.now_override = Time.parse( '1986-5-21 4:17 am UTC' )
233
229
  end
234
230
 
231
+ def log_error_callback(data, ex)
232
+ @fail_count += 1
233
+ end
234
+
235
+
235
236
  should "include the timestamp when the exception is logged" do
236
237
  mock(ExceptionHandling.logger).fatal(/\(Error:517033020\) ArgumentError mooo \(blah\):\n.*exception_handling_test\.rb/)
237
238
  b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError.new("blah") }
@@ -252,12 +253,15 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
252
253
  assert_match(/Exception 2/, ActionMailer::Base.deliveries[-1].subject)
253
254
  end
254
255
 
255
- should "only send 5 of a repeated error" do
256
+ should "only send 5 of a repeated error, but call post hook for every exception" do
257
+ @fail_count = 0
258
+ ExceptionHandling.post_log_error_hook = method(:log_error_callback)
256
259
  assert_emails 5 do
257
260
  10.times do
258
261
  ExceptionHandling.log_error(exception_1)
259
262
  end
260
263
  end
264
+ assert_equal 10, @fail_count
261
265
  end
262
266
 
263
267
  should "only send 5 of a repeated error but don't send summary if 6th is different" do
@@ -671,25 +675,6 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
671
675
  end
672
676
  end
673
677
 
674
- context "Errplane" do
675
- module ErrplaneStub
676
- end
677
-
678
- setup do
679
- set_test_const('Errplane', ErrplaneStub)
680
- end
681
-
682
- should "forward exceptions" do
683
- mock(Errplane).transmit(exception_1, anything)
684
- ExceptionHandling.log_error(exception_1, "context")
685
- end
686
-
687
- should "not forward warnings" do
688
- stub(Errplane).transmit.times(0)
689
- ExceptionHandling.log_warning("warning message")
690
- end
691
- end
692
-
693
678
  private
694
679
 
695
680
  def incrementing_mtime
@@ -27,6 +27,14 @@
27
27
  <br />
28
28
  <br />
29
29
 
30
+ <% if @cleaned_data[:notes] %>
31
+ <b>Exception Notes:</b> (from config/exception.yml)<br />
32
+ <%= @cleaned_data[:notes].gsub("\n","<br/>\n").gsub(/ {2,}/) { |spaces| '&nbsp;'*spaces.size }.html_safe %>
33
+ <br />
34
+ <br />
35
+ <% end %>
36
+
37
+
30
38
  <b>User summary:</b><br />
31
39
  <% if (user_details = @cleaned_data[:user_details]) && ( user_details[:user] || user_details[:organization] ) %>
32
40
  User: <%= user_details[:user] %> (<%= user_details[:username] %>)<br />
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exception_handling
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Colin Kelley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-28 00:00:00.000000000 Z
11
+ date: 2014-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eventmachine
@@ -167,12 +167,16 @@ files:
167
167
  - config/exception_filters.yml
168
168
  - exception_handling.gemspec
169
169
  - lib/exception_handling.rb
170
+ - lib/exception_handling/exception_catalog.rb
171
+ - lib/exception_handling/exception_description.rb
170
172
  - lib/exception_handling/log_stub_error.rb
171
173
  - lib/exception_handling/mailer.rb
172
174
  - lib/exception_handling/methods.rb
173
175
  - lib/exception_handling/testing.rb
174
176
  - lib/exception_handling/version.rb
175
177
  - test/test_helper.rb
178
+ - test/unit/exception_handling/exception_catalog_test.rb
179
+ - test/unit/exception_handling/exception_description_test.rb
176
180
  - test/unit/exception_handling/log_error_stub_test.rb
177
181
  - test/unit/exception_handling/mailer_test.rb
178
182
  - test/unit/exception_handling/methods_test.rb
@@ -206,6 +210,8 @@ summary: Invoca's exception handling logger/emailer layer, based on exception_no
206
210
  Works with Rails or EventMachine or EventMachine+Synchrony.
207
211
  test_files:
208
212
  - test/test_helper.rb
213
+ - test/unit/exception_handling/exception_catalog_test.rb
214
+ - test/unit/exception_handling/exception_description_test.rb
209
215
  - test/unit/exception_handling/log_error_stub_test.rb
210
216
  - test/unit/exception_handling/mailer_test.rb
211
217
  - test/unit/exception_handling/methods_test.rb