party_foul 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -16,10 +16,10 @@ following:
16
16
  unique title, session information, and stack trace. The issue is
17
17
  tagged as a `bug`. A new comment is added with relevant data on the
18
18
  application state.
19
- 3. If an open issue is found the occurance count and time stamp is
19
+ 3. If an open issue is found the occurence count and time stamp is
20
20
  updated. A new comment is added with relevant data on the
21
21
  application state.
22
- 4. If a closed issue is found the occurance count and time stamp is
22
+ 4. If a closed issue is found the occurence count and time stamp is
23
23
  updated. The issue is reopened and a `regression` tag is
24
24
  added. A new comment is added with relevant data on the
25
25
  application state.
@@ -64,32 +64,29 @@ You need to initialize `PartyFoul`, use the following:
64
64
 
65
65
  ```ruby
66
66
  PartyFoul.configure do |config|
67
- # the collection of exceptions to be ignored by PartyFoul
67
+ # The collection of exceptions PartyFoul should not be allowed to handle
68
68
  # The constants here *must* be represented as strings
69
- config.ignored_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
70
-
71
- # The names of the HTTP headers to not report
72
- config.filtered_http_headers = ['Cookie']
69
+ config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
73
70
 
74
71
  # The OAuth token for the account that is opening the issues on Github
75
- config.oauth_token = 'abcdefgh1234567890'
72
+ config.oauth_token = 'abcdefgh1234567890'
76
73
 
77
74
  # The API endpoint for Github. Unless you are hosting a private
78
75
  # instance of Enterprise Github you do not need to include this
79
- config.endpoint = 'https://api.github.com'
76
+ config.endpoint = 'https://api.github.com'
80
77
 
81
78
  # The Web URL for Github. Unless you are hosting a private
82
79
  # instance of Enterprise Github you do not need to include this
83
- config.web_url = 'https://github.com'
80
+ config.web_url = 'https://github.com'
84
81
 
85
82
  # The organization or user that owns the target repository
86
- config.owner = 'owner_name'
83
+ config.owner = 'owner_name'
87
84
 
88
85
  # The repository for this application
89
- config.repo = 'repo_name'
86
+ config.repo = 'repo_name'
90
87
 
91
88
  # The branch for your deployed code
92
- # config.branch = 'master'
89
+ # config.branch = 'master'
93
90
  end
94
91
  ```
95
92
 
@@ -98,8 +95,8 @@ You can generate an OAuth token from via the
98
95
  with cURL:
99
96
 
100
97
  ```bash
101
- curl -X POST -i -d "{ \"scopes\": [\"repo\"] }" \
102
- https://<github_login>:<github_password>@api.github.com/authorizations
98
+ curl -u <github_login> -i -d "{ \"scopes\": [\"repo\"] }" \
99
+ https://api.github.com/authorizations
103
100
  ```
104
101
 
105
102
  Add as the very last middleware in your production `Rack` stack.
@@ -128,25 +125,34 @@ end
128
125
 
129
126
  ```
130
127
 
131
- ### Changing How Issues Are Reported ###
128
+ ### Using PartyFoul with Sidekiq
129
+
130
+ In order to use PartyFoul for exception handling with Sidekiq you will need to create an initializer with some middleware configuration. The following example is based on using [Sidekiq with another exception notifiier server](https://github.com/bugsnag/bugsnag-ruby/blob/master/lib/bugsnag/sidekiq.rb).
132
131
 
133
- `PartyFoul` comes with default templates for what the body of issues and
134
- comments are. If you want to override these templates you simply need to
135
- add them as an option in your initializer:
132
+ File: config/initializers/partyfoul_sidekiq.rb
136
133
 
137
134
  ```ruby
138
- PartyFoul.configure do |config|
139
- config.issue_body = ':issue_title'
140
- config.comment_body = ':occurred_at'
135
+ module PartyFoul
136
+ class Sidekiq
137
+ def call(worker, msg, queue)
138
+ begin
139
+ yield
140
+ rescue => ex
141
+ PartyFoul::RacklessExceptionHandler.handle(ex, {class: worker.class.name, method: queue, params: msg})
142
+ raise
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ ::Sidekiq.configure_server do |config|
149
+ config.server_middleware do |chain|
150
+ chain.add ::PartyFoul::Sidekiq
151
+ end
141
152
  end
142
153
  ```
143
154
 
144
- In this over-simplistic example the words that start with `:` in the
145
- templates are evaluated with the value of the corresponding named
146
- instance method on the instance of `PartyFoul::IssueRenderer`. If you
147
- want to add additional values for replacement you should open that class
148
- to add the methods. Depending upon the data point you may want o make
149
- the change in one of the [different issue renderer adapters](https://github.com/dockyard/party_foul/tree/master/lib/party_foul/issue_renderers).
155
+ This will pass the worker class name and queue as well as all worker-related parameters off to PartyFoul before passing on the exception.
150
156
 
151
157
  ## Authors ##
152
158
 
@@ -1,28 +1,25 @@
1
1
  PartyFoul.configure do |config|
2
- # the collection of exceptions to be ignored by PartyFoul
2
+ # The collection of exceptions PartyFoul should not be allowed to handle
3
3
  # The constants here *must* be represented as strings
4
- config.ignored_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
5
-
6
- # The names of the HTTP headers to not report
7
- config.filtered_http_headers = ['Cookie']
4
+ config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
8
5
 
9
6
  # The OAuth token for the account that is opening the issues on Github
10
- config.oauth_token = '<%= @oauth_token %>'
7
+ config.oauth_token = '<%= @oauth_token %>'
11
8
 
12
9
  # The API endpoint for Github. Unless you are hosting a private
13
10
  # instance of Enterprise Github you do not need to include this
14
- config.endpoint = '<%= @endpoint %>'
11
+ config.endpoint = '<%= @endpoint %>'
15
12
 
16
13
  # The Web URL for Github. Unless you are hosting a private
17
14
  # instance of Enterprise Github you do not need to include this
18
- config.web_url = '<%= @web_url %>'
15
+ config.web_url = '<%= @web_url %>'
19
16
 
20
17
  # The organization or user that owns the target repository
21
- config.owner = '<%= @owner %>'
18
+ config.owner = '<%= @owner %>'
22
19
 
23
20
  # The repository for this application
24
- config.repo = '<%= @repo %>'
21
+ config.repo = '<%= @repo %>'
25
22
 
26
23
  # The branch for your deployed code
27
- # config.branch = 'master'
24
+ # config.branch = 'master'
28
25
  end
@@ -2,9 +2,11 @@ require 'github_api'
2
2
 
3
3
  module PartyFoul
4
4
  class << self
5
- attr_accessor :github, :oauth_token, :endpoint, :owner, :repo,
6
- :ignored_exceptions, :processor, :issue_template,
7
- :comment_template, :filtered_http_headers, :web_url, :branch
5
+ attr_accessor :github, :oauth_token, :endpoint, :owner, :repo, :blacklisted_exceptions, :processor, :web_url, :branch, :whitelisted_rack_variables
6
+ end
7
+
8
+ def self.whitelisted_rack_variables
9
+ @whitelisted_rack_variables ||= %w{GATEWAY_INTERFACE PATH_INFO REMOTE_ADDR REMOTE_HOST REQUEST_METHOD REQUEST_URI SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE HTTP_HOST HTTP_CONNECTION HTTP_CACHE_CONTROL HTTP_ACCEPT HTTP_USER_AGENT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_ACCEPT_CHARSET rack.version rack.input rack.errors rack.multithread rack.multiprocess rack.run_once rack.url_scheme HTTP_VERSION REQUEST_PATH ORIGINAL_FULLPATH action_dispatch.routes action_dispatch.parameter_filter action_dispatch.secret_token action_dispatch.show_exceptions action_dispatch.show_detailed_exceptions action_dispatch.logger action_dispatch.backtrace_cleaner action_dispatch.request_id action_dispatch.remote_ip rack.session rack.session.options rack.request.cookie_hash rack.request.cookie_string action_dispatch.cookies action_dispatch.request.unsigned_session_cookie action_dispatch.request.path_parameters action_controller.instance action_dispatch.request.request_parameters rack.request.query_string rack.request.query_hash action_dispatch.request.query_parameters action_dispatch.request.parameters action_dispatch.request.formats}
8
10
  end
9
11
 
10
12
  # The git branch that is used for linking in the stack trace
@@ -22,38 +24,20 @@ module PartyFoul
22
24
  @web_url ||= 'https://github.com'
23
25
  end
24
26
 
25
- # The template used for rendering the body of a new issue
27
+ # The api endpoint for Github. This is only interesting for Enterprise
28
+ # users
26
29
  #
27
- # @return [String]
28
- def self.issue_template
29
- @issue_template ||=
30
- <<-TEMPLATE
31
- <table>
32
- <tr><th>Exception</th><td>:exception</td></tr>
33
- <tr><th>Count</th><td>1</td></tr>
34
- <tr><th>Last Occurance</th><td>:occurred_at</td></tr>
35
- </table>
36
-
37
- ## Stack Trace
38
- <pre>:stack_trace</pre>
39
- Fingerprint: `:fingerprint`
40
- TEMPLATE
30
+ # @return [String] Defaults to 'https://api.github.com' if not set
31
+ def self.endpoint
32
+ @endpoint ||= 'https://api.github.com'
41
33
  end
42
34
 
43
- # The template used for rendering the body of a new comment
35
+ # The processor to be used when handling the exception. Defaults to a
36
+ # synchrons processor
44
37
  #
45
- # @return [String]
46
- def self.comment_template
47
- @comment_template ||=
48
- <<-TEMPLATE
49
- <table>
50
- <tr><th>Occurred at</th><td>:occurred_at</td></tr>
51
- <tr><th>Params</th><td>:params</td></tr>
52
- <tr><th>IP Address</th><td>:ip_address</td></tr>
53
- <tr><th>Session</th><td>:session</td></tr>
54
- <tr><th>HTTP Headers</th><td>:http_headers</td></tr>
55
- </table>
56
- TEMPLATE
38
+ # @return [Class] Defaults to 'PartyFoul::Processors:Sync
39
+ def self.processor
40
+ @processor ||= PartyFoul::Processors::Sync
57
41
  end
58
42
 
59
43
  # The collection of exceptions that should not be captured. Members of
@@ -67,8 +51,8 @@ Fingerprint: `:fingerprint`
67
51
  # [ActiveRecord::RecordNotFound]
68
52
  #
69
53
  # @return [Array]
70
- def self.ignored_exceptions
71
- @ignored_exceptions || []
54
+ def self.blacklisted_exceptions
55
+ @blacklisted_exceptions || []
72
56
  end
73
57
 
74
58
  # The url of the repository. Built using the {.web_url}, {.owner}, and {.repo}
@@ -87,20 +71,17 @@ Fingerprint: `:fingerprint`
87
71
  # config.oauth_token = ENV['oauth_token']
88
72
  # end
89
73
  #
74
+ # Will also setup for Github api connections
75
+ #
90
76
  # @param [Block]
91
77
  def self.configure(&block)
92
78
  yield self
93
- self.processor ||= PartyFoul::Processors::Sync
94
- _self = self
95
- self.github ||= Github.new do |config|
96
- %w{endpoint oauth_token}.each do |option|
97
- config.send("#{option}=", _self.send(option)) if !_self.send(option).nil?
98
- end
99
- end
79
+ self.github ||= Github.new oauth_token: oauth_token, endpoint: endpoint
100
80
  end
101
81
  end
102
82
 
103
83
  require 'party_foul/exception_handler'
104
- require 'party_foul/issue_renderer'
84
+ require 'party_foul/rackless_exception_handler'
85
+ require 'party_foul/issue_renderers'
105
86
  require 'party_foul/middleware'
106
87
  require 'party_foul/processors'
@@ -7,7 +7,7 @@ class PartyFoul::ExceptionHandler
7
7
  #
8
8
  # @param [Exception, Hash]
9
9
  def self.handle(exception, env)
10
- PartyFoul.processor.handle(exception, env)
10
+ PartyFoul.processor.handle(exception, clean_env(env))
11
11
  end
12
12
 
13
13
  # Makes an attempt to determine what framework is being used and will use the proper
@@ -16,9 +16,9 @@ class PartyFoul::ExceptionHandler
16
16
  # @param [Exception, Hash]
17
17
  def initialize(exception, env)
18
18
  renderer_klass = if defined?(Rails)
19
- PartyFoul::RailsIssueRenderer
19
+ PartyFoul::IssueRenderers::Rails
20
20
  else
21
- PartyFoul::RackIssueRenderer
21
+ PartyFoul::IssueRenderers::Rack
22
22
  end
23
23
 
24
24
  self.rendered_issue = renderer_klass.new(exception, env)
@@ -69,6 +69,10 @@ class PartyFoul::ExceptionHandler
69
69
 
70
70
  private
71
71
 
72
+ def self.clean_env(env)
73
+ env.select { |key, value| PartyFoul.whitelisted_rack_variables.include?(key) }
74
+ end
75
+
72
76
  def fingerprint
73
77
  rendered_issue.fingerprint
74
78
  end
@@ -0,0 +1,5 @@
1
+ module PartyFoul::IssueRenderers; end
2
+ require 'party_foul/issue_renderers/base'
3
+ require 'party_foul/issue_renderers/rack'
4
+ require 'party_foul/issue_renderers/rails'
5
+ require 'party_foul/issue_renderers/rackless'
@@ -1,4 +1,4 @@
1
- class PartyFoul::IssueRenderer
1
+ class PartyFoul::IssueRenderers::Base
2
2
  attr_accessor :exception, :env, :sha
3
3
 
4
4
  # A new renderer instance for Githug issues
@@ -16,18 +16,27 @@ class PartyFoul::IssueRenderer
16
16
  raise NotImplementedError
17
17
  end
18
18
 
19
- # Will compile the template for an issue body as defined in
20
- # {PartyFoul.issue_template}
19
+ # Renders the issue body
20
+ #
21
+ # Customize by overriding {#body_options}
21
22
  #
22
23
  # @return [String]
23
24
  def body
24
- compile_template(PartyFoul.issue_template)
25
+ <<-BODY
26
+ #{build_table_from_hash(body_options)}
27
+
28
+ ## Stack Trace
29
+ <pre>#{stack_trace}</pre>
30
+ Fingerprint: `#{fingerprint}`
31
+ BODY
25
32
  end
26
33
 
27
- # Will compile the template for a comment body as defined in
28
- # {PartyFoul.comment_template}
34
+ # Renderes the issue comment
35
+ #
36
+ # Customize by overriding {#comment_options}
37
+ #
29
38
  def comment
30
- compile_template(PartyFoul.comment_template)
39
+ build_table_from_hash(comment_options)
31
40
  end
32
41
 
33
42
  # Compiles the stack trace for use in the issue body. Lines in the
@@ -67,21 +76,13 @@ class PartyFoul::IssueRenderer
67
76
  begin
68
77
  current_count = old_body.match(/<th>Count<\/th><td>(\d+)<\/td>/)[1].to_i
69
78
  old_body.sub!("<th>Count</th><td>#{current_count}</td>", "<th>Count</th><td>#{current_count + 1}</td>")
70
- old_body.sub!(/<th>Last Occurance<\/th><td>.+<\/td>/, "<th>Last Occurance</th><td>#{occurred_at}</td>")
79
+ old_body.sub!(/<th>Last Occurrence<\/th><td>.+<\/td>/, "<th>Last Occurrence</th><td>#{occurred_at}</td>")
71
80
  old_body
72
81
  rescue
73
82
  self.body
74
83
  end
75
84
  end
76
85
 
77
- # The params hash at the time the exception occurred. This method is
78
- # overriden for each framework adapter. It should return a hash.
79
- #
80
- # @return [NotImplementedError]
81
- def params
82
- raise NotImplementedError
83
- end
84
-
85
86
  # The timestamp when the exception occurred.
86
87
  #
87
88
  # @return [String]
@@ -89,48 +90,45 @@ class PartyFoul::IssueRenderer
89
90
  Time.now.strftime('%B %d, %Y %H:%M:%S %z')
90
91
  end
91
92
 
92
- # IP address of the client who triggered the exception
93
+ # The hash used for building the table in issue body
93
94
  #
94
- # @return [String]
95
- def ip_address
96
- env['REMOTE_ADDR']
95
+ # @return [Hash]
96
+ def body_options(count = 0)
97
+ { Exception: exception, 'Last Occurrence' => occurred_at, Count: count + 1 }
97
98
  end
98
99
 
99
- # The session hash for the client at the time of the exception
100
+ # The hash used for building the table in the comment body
100
101
  #
101
102
  # @return [Hash]
102
- def session
103
- env['rack.session']
103
+ def comment_options
104
+ { 'Occurred At' => occurred_at }
104
105
  end
105
106
 
106
- # HTTP Headers hash from the request. Headers can be filtered out by
107
- # adding matching key names to {PartyFoul.filtered_http_headers}
107
+
108
+ # Builds an HTML table from hash
108
109
  #
109
- # @return [Hash]
110
- def http_headers
111
- env.keys.select { |key| key =~ /^HTTP_(\w+)/ && !(PartyFoul.filtered_http_headers || []).include?($1.split('_').map(&:capitalize).join('-')) }.sort.inject({}) do |hash, key|
112
- hash[key.split('HTTP_').last.split('_').map(&:capitalize).join('-')] = env[key]
113
- hash
114
- end
110
+ # @return [String]
111
+ def build_table_from_hash(hash)
112
+ "<table>#{rows_for_table_from_hash(hash)}</table>"
115
113
  end
116
114
 
117
- def compile_template(template)
118
- template.gsub(/:\w+/) do |method|
119
- value = self.send(method.split(':').last)
120
- if value.kind_of?(Hash)
121
- hash_as_table(value)
122
- else
123
- value
115
+ # Builds the rows of an HTML table from hash.
116
+ # Keys as Headers cells and Values as Data cells
117
+ # If the Value is a Hash it will be rendered as a table
118
+ #
119
+ # @return [String]
120
+ def rows_for_table_from_hash(hash)
121
+ hash.inject('') do |rows, row|
122
+ key, value = row
123
+ if row[1].kind_of?(Hash)
124
+ value = build_table_from_hash(row[1])
124
125
  end
126
+ rows << "<tr><th>#{key}</th><td>#{value}</td></tr>"
125
127
  end
126
128
  end
127
129
 
128
130
  private
129
131
 
130
- def hash_as_table(value)
131
- "<table>#{value.map {|key, value| "<tr><th>#{key}</th><td>#{value}</td></tr>"}.join}</table>"
132
- end
133
-
134
132
  def app_root
135
133
  Dir.pwd
136
134
  end
@@ -139,6 +137,3 @@ class PartyFoul::IssueRenderer
139
137
  backtrace_line.match(/#{app_root}\/((.+?):(\d+))/)
140
138
  end
141
139
  end
142
-
143
- require 'party_foul/issue_renderers/rack'
144
- require 'party_foul/issue_renderers/rails'
@@ -1,19 +1,45 @@
1
- require 'party_foul/issue_renderer'
1
+ class PartyFoul::IssueRenderers::Rack < PartyFoul::IssueRenderers::Base
2
+ # Title for the issue comprised of (exception) "message"
3
+ #
4
+ # @return [String]
5
+ def title
6
+ %{(#{exception.class}) "#{exception.message}"}
7
+ end
8
+
9
+ def comment_options
10
+ super.merge(URL: url, Params: params, Session: session, 'IP Address' => ip_address, 'HTTP Headers' => http_headers)
11
+ end
12
+
13
+ # Rack params
14
+ #
15
+ # @return [Hash]
16
+ def params
17
+ env['QUERY_STRING']
18
+ end
2
19
 
3
- module PartyFoul
4
- class RackIssueRenderer < IssueRenderer
5
- # Rack params
6
- #
7
- # @return [Hash]
8
- def params
9
- env['QUERY_STRING']
10
- end
20
+ # IP address of the client who triggered the exception
21
+ #
22
+ # @return [String]
23
+ def ip_address
24
+ env['REMOTE_ADDR']
25
+ end
26
+
27
+ def url
28
+ "[#{env['REQUEST_METHOD']}] #{env['REQUEST_URI']}"
29
+ end
30
+
31
+ # The session hash for the client at the time of the exception
32
+ #
33
+ # @return [Hash]
34
+ def session
35
+ env['rack.session']
36
+ end
11
37
 
12
- # Title for the issue comprised of (exception) "message"
13
- #
14
- # @return [String]
15
- def title
16
- %{(#{exception.class}) "#{exception.message}"}
17
- end
38
+ # HTTP Headers hash from the request. Headers can be filtered out by
39
+ # adding matching key names to {PartyFoul.blacklisted_headers}
40
+ #
41
+ # @return [Hash]
42
+ def http_headers
43
+ { Version: env['HTTP_VERSION'], 'User Agent' => env['HTTP_USER_AGENT'], 'Accept Encoding' => env['HTTP_ACCEPT_ENCODING'], Accept: env['HTTP_ACCEPT'] }
18
44
  end
19
45
  end
@@ -0,0 +1,26 @@
1
+ require 'party_foul/issue_renderers/base'
2
+
3
+ class PartyFoul::IssueRenderers::Rackless < PartyFoul::IssueRenderers::Base
4
+ # env in a rackless environment is expected to contain three keys:
5
+ # class: name of the class that raised the exception
6
+ # method: name of the method that raised the exception
7
+ # params: parameters passed to the method that raised the exception
8
+
9
+ # Rails params hash. Filtered parms are respected.
10
+ #
11
+ # @return [Hash]
12
+ def params
13
+ env[:params]
14
+ end
15
+
16
+ # Title for the issue comprised of Controller#action (exception) "message"
17
+ #
18
+ # @return [String]
19
+ def title
20
+ %{#{env[:class]}##{env[:method]} (#{exception.class}) "#{exception.message}"}
21
+ end
22
+
23
+ def comment_options
24
+ super.merge(Params: params)
25
+ end
26
+ end
@@ -1,26 +1,30 @@
1
- require 'party_foul/issue_renderer'
1
+ class PartyFoul::IssueRenderers::Rails < PartyFoul::IssueRenderers::Rack
2
+ # Title for the issue comprised of Controller#action (exception) "message"
3
+ #
4
+ # @return [String]
5
+ def title
6
+ %{#{env['action_controller.instance'].class}##{env['action_dispatch.request.path_parameters']['action']} (#{exception.class}) "#{exception.message}"}
7
+ end
2
8
 
3
- module PartyFoul
4
- class RailsIssueRenderer < IssueRenderer
5
- # Rails params hash. Filtered parms are respected.
6
- #
7
- # @return [Hash]
8
- def params
9
- parameter_filter = ActionDispatch::Http::ParameterFilter.new(env["action_dispatch.parameter_filter"])
10
- parameter_filter.filter(env['action_dispatch.request.path_parameters'])
11
- end
9
+ # Rails params hash. Filtered parms are respected.
10
+ #
11
+ # @return [Hash]
12
+ def params
13
+ parameter_filter = ActionDispatch::Http::ParameterFilter.new(env["action_dispatch.parameter_filter"])
14
+ parameter_filter.filter(env['action_dispatch.request.path_parameters'])
15
+ end
12
16
 
13
- # Title for the issue comprised of Controller#action (exception) "message"
14
- #
15
- # @return [String]
16
- def title
17
- %{#{env['action_controller.instance'].class}##{env['action_dispatch.request.path_parameters']['action']} (#{exception.class}) "#{exception.message}"}
18
- end
17
+ # Rails session hash. Filtered parms are respected.
18
+ #
19
+ # @return [Hash]
20
+ def session
21
+ parameter_filter = ActionDispatch::Http::ParameterFilter.new(env['action_dispatch.parameter_filter'])
22
+ parameter_filter.filter(env['rack.session'])
23
+ end
19
24
 
20
- private
25
+ private
21
26
 
22
- def app_root
23
- Rails.root
24
- end
27
+ def app_root
28
+ Rails.root
25
29
  end
26
30
  end
@@ -16,8 +16,8 @@ module PartyFoul
16
16
  private
17
17
 
18
18
  def allow_handling?(captured_exception)
19
- !PartyFoul.ignored_exceptions.find do |ignored_exception|
20
- names = ignored_exception.split('::')
19
+ !PartyFoul.blacklisted_exceptions.find do |blacklisted_exception|
20
+ names = blacklisted_exception.split('::')
21
21
  names.shift if names.empty? || names.first.empty?
22
22
 
23
23
  constant = Object
@@ -1,4 +1,2 @@
1
- module PartyFoul::Processors
2
- end
3
-
1
+ module PartyFoul::Processors; end
4
2
  require 'party_foul/processors/sync'
@@ -0,0 +1,11 @@
1
+ class PartyFoul::Processors::Base
2
+ # Passes the exception and rack env data to the ExceptionHandler and
3
+ # runs everything synchronously. This base class method must be
4
+ # overriden by any inheriting class.
5
+ #
6
+ # @param [Exception, Hash]
7
+ # @return [NotImplementedError]
8
+ def self.handle(exception, env)
9
+ raise NotImplementedError
10
+ end
11
+ end
@@ -1,4 +1,6 @@
1
- class PartyFoul::Processors::Sync
1
+ require 'party_foul/processors/base'
2
+
3
+ class PartyFoul::Processors::Sync < PartyFoul::Processors::Base
2
4
  # Passes the exception and rack env data to the ExceptionHandler and
3
5
  # runs everything synchronously.
4
6
  #
@@ -0,0 +1,17 @@
1
+ class PartyFoul::RacklessExceptionHandler < PartyFoul::ExceptionHandler
2
+ # This handler will pass the exception and working environment from Rack off to a processor.
3
+ # The default PartyFoul processor will work synchronously. Processor adapters can be written
4
+ # to push this logic to a background job if desired.
5
+ #
6
+ # @param [Exception, Hash]
7
+ def self.handle(exception, env)
8
+ self.new(exception, clean_env(env)).run
9
+ end
10
+
11
+ # Uses the Rackless IssueRenderer for a rackless environment
12
+ #
13
+ # @param [Exception, Hash]
14
+ def initialize(exception, env)
15
+ self.rendered_issue = PartyFoul::IssueRenderers::Rackless.new(exception, env)
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module PartyFoul
2
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
3
3
  end
@@ -8,7 +8,7 @@ describe 'Party Foul Confg' do
8
8
 
9
9
  it 'sets the proper config variables' do
10
10
  PartyFoul.configure do |config|
11
- config.ignored_exceptions = ['StandardError']
11
+ config.blacklisted_exceptions = ['StandardError']
12
12
  config.oauth_token = 'test_token'
13
13
  config.web_url = 'http://example.com'
14
14
  config.endpoint = 'http://api.example.com'
@@ -17,7 +17,7 @@ describe 'Party Foul Confg' do
17
17
  config.branch = 'master'
18
18
  end
19
19
 
20
- PartyFoul.ignored_exceptions.must_equal ['StandardError']
20
+ PartyFoul.blacklisted_exceptions.must_equal ['StandardError']
21
21
  PartyFoul.github.must_be_instance_of Github::Client
22
22
  PartyFoul.github.oauth_token.must_equal 'test_token'
23
23
  PartyFoul.github.endpoint.must_equal 'http://api.example.com'
@@ -16,14 +16,14 @@ describe 'Party Foul Exception Handler' do
16
16
  PartyFoul.github.issues.stubs(:edit)
17
17
  PartyFoul.github.issues.stubs(:comments).returns(mock('Comments'))
18
18
  PartyFoul.github.issues.comments.stubs(:create)
19
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:title).returns('Test Title')
20
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:fingerprint).returns('test_fingerprint')
19
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:title).returns('Test Title')
20
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:fingerprint).returns('test_fingerprint')
21
21
  end
22
22
 
23
23
  context 'when error is new' do
24
24
  it 'will open a new error on Github' do
25
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:body).returns('Test Body')
26
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:comment).returns('Test Comment')
25
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:body).returns('Test Body')
26
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:comment).returns('Test Comment')
27
27
  PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
28
28
  PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: []))
29
29
  PartyFoul.github.issues.expects(:create).with('test_owner', 'test_repo', title: 'Test Title', body: 'Test Body', :labels => ['bug']).returns(Hashie::Mash.new('number' => 1))
@@ -35,8 +35,8 @@ describe 'Party Foul Exception Handler' do
35
35
 
36
36
  context 'when error is not new' do
37
37
  before do
38
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:update_body).returns('New Body')
39
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:comment).returns('Test Comment')
38
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:update_body).returns('New Body')
39
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:comment).returns('Test Comment')
40
40
  end
41
41
 
42
42
  context 'and open' do
@@ -63,7 +63,7 @@ describe 'Party Foul Exception Handler' do
63
63
 
64
64
  context 'when issue is marked as "wontfix"' do
65
65
  it 'does nothing' do
66
- PartyFoul::RailsIssueRenderer.any_instance.stubs(:body).returns('Test Body')
66
+ PartyFoul::IssueRenderers::Rails.any_instance.stubs(:body).returns('Test Body')
67
67
  PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'open').returns(Hashie::Mash.new(issues: []))
68
68
  PartyFoul.github.search.stubs(:issues).with(owner: 'test_owner', repo: 'test_repo', keyword: 'test_fingerprint', state: 'closed').returns(Hashie::Mash.new(issues: [{title: 'Test Title', body: 'Test Body', state: 'closed', number: 1, 'labels' => ['wontfix']}]))
69
69
  PartyFoul.github.issues.expects(:create).never
@@ -0,0 +1,91 @@
1
+ require 'test_helper'
2
+ require 'active_support/core_ext/object/blank'
3
+ require 'action_dispatch/http/parameter_filter'
4
+
5
+ describe 'Party Foul Issue Renderer Base' do
6
+ before do
7
+ Time.stubs(:now).returns(Time.new(1970, 1, 1, 0, 0, 0, '-05:00'))
8
+ end
9
+
10
+ after do
11
+ clean_up_party
12
+ end
13
+
14
+ describe '#body' do
15
+ describe 'updating issue body' do
16
+ before do
17
+ @rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
18
+ @rendered_issue.stubs(:exception).returns('Test Exception')
19
+ @rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
20
+ @rendered_issue.stubs(:stack_trace)
21
+ end
22
+
23
+ it 'updates count and timestamp' do
24
+ body = <<-BODY
25
+ <table>
26
+ <tr><th>Exception</th><td>Test Exception</td></tr>
27
+ <tr><th>Count</th><td>1</td></tr>
28
+ <tr><th>Last Occurrence</th><td>January 01, 1970 00:00:00 -0500</td></tr>
29
+ </table>
30
+
31
+ ## Stack Trace
32
+ <pre></pre>
33
+ Fingerprint: `abcdefg1234567890`
34
+ BODY
35
+
36
+ Time.stubs(:now).returns(Time.new(1985, 10, 25, 1, 22, 0, '-05:00'))
37
+
38
+ expected_body = <<-BODY
39
+ <table>
40
+ <tr><th>Exception</th><td>Test Exception</td></tr>
41
+ <tr><th>Count</th><td>2</td></tr>
42
+ <tr><th>Last Occurrence</th><td>October 25, 1985 01:22:00 -0500</td></tr>
43
+ </table>
44
+
45
+ ## Stack Trace
46
+ <pre></pre>
47
+ Fingerprint: `abcdefg1234567890`
48
+ BODY
49
+
50
+ @rendered_issue.update_body(body).must_equal expected_body
51
+ end
52
+ end
53
+
54
+ describe 'empty body' do
55
+ before do
56
+ @rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
57
+ @rendered_issue.stubs(:exception).returns('Test Exception')
58
+ @rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
59
+ @rendered_issue.stubs(:stack_trace)
60
+ end
61
+
62
+ it 'resets body' do
63
+ expected_body = <<-BODY
64
+ <table><tr><th>Exception</th><td>Test Exception</td></tr><tr><th>Last Occurrence</th><td>January 01, 1970 00:00:00 -0500</td></tr><tr><th>Count</th><td>1</td></tr></table>
65
+
66
+ ## Stack Trace
67
+ <pre></pre>
68
+ Fingerprint: `abcdefg1234567890`
69
+ BODY
70
+ @rendered_issue.update_body(nil).must_equal expected_body
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#build_table_from_hash' do
76
+ it 'builds an HTML table from a hash' do
77
+ rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
78
+ hash = { 'Value 1' => 'abc', 'Value 2' => { 'Value A' => 123, 'Value B' => 456 } }
79
+ expected = '<table><tr><th>Value 1</th><td>abc</td></tr><tr><th>Value 2</th><td><table><tr><th>Value A</th><td>123</td></tr><tr><th>Value B</th><td>456</td></tr></table></td></tr></table>'
80
+ rendered_issue.build_table_from_hash(hash).must_equal expected
81
+ end
82
+ end
83
+
84
+ describe '#fingerprint' do
85
+ it 'SHA1s the title' do
86
+ rendered_issue = PartyFoul::IssueRenderers::Base.new(nil, nil)
87
+ rendered_issue.stubs(:title).returns('abcdefg1234567890')
88
+ rendered_issue.fingerprint.must_equal Digest::SHA1.hexdigest(rendered_issue.title)
89
+ end
90
+ end
91
+ end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  describe 'Rack Issue Renderer' do
4
4
  describe '#params' do
5
5
  before do
6
- @rendered_issue = PartyFoul::RackIssueRenderer.new(nil, {'QUERY_STRING' => { 'status' => 'ok' } })
6
+ @rendered_issue = PartyFoul::IssueRenderers::Rack.new(nil, {'QUERY_STRING' => { 'status' => 'ok' } })
7
7
  end
8
8
 
9
9
  it 'returns ok' do
@@ -17,7 +17,7 @@ describe 'Rack Issue Renderer' do
17
17
  end
18
18
 
19
19
  it 'constructs the title with the class and instance method' do
20
- @rendered_issue = PartyFoul::RackIssueRenderer.new(@exception, {})
20
+ @rendered_issue = PartyFoul::IssueRenderers::Rack.new(@exception, {})
21
21
  @rendered_issue.title.must_equal %{(Exception) "message"}
22
22
  end
23
23
  end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ describe 'Rackless Issue Renderer' do
4
+ before do
5
+ @env = { :params => { :val1 => '1', :val2 => '2' }, :class => 'Worker', :method => 'perform' }
6
+ end
7
+
8
+ describe '#params' do
9
+ before do
10
+ @rendered_issue = PartyFoul::IssueRenderers::Rackless.new(nil, @env)
11
+ end
12
+
13
+ it 'returns the parameters' do
14
+ @rendered_issue.params[:val1].must_equal '1'
15
+ @rendered_issue.params[:val2].must_equal '2'
16
+ end
17
+ end
18
+
19
+ describe '#title' do
20
+ before do
21
+ @exception = Exception.new('message')
22
+ @rendered_issue = PartyFoul::IssueRenderers::Rackless.new(@exception, @env)
23
+ end
24
+
25
+ it 'constructs the title with the controller and action' do
26
+ @rendered_issue.title.must_equal %{Worker#perform (Exception) "message"}
27
+ end
28
+ end
29
+ end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  describe 'Rails Issue Renderer' do
4
4
  describe '#params' do
5
5
  before do
6
- @rendered_issue = PartyFoul::RailsIssueRenderer.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'action_dispatch.request.path_parameters' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
6
+ @rendered_issue = PartyFoul::IssueRenderers::Rails.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'action_dispatch.request.path_parameters' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
7
7
  end
8
8
 
9
9
  it 'returns ok' do
@@ -12,6 +12,17 @@ describe 'Rails Issue Renderer' do
12
12
  end
13
13
  end
14
14
 
15
+ describe '#session' do
16
+ before do
17
+ @rendered_issue = PartyFoul::IssueRenderers::Rails.new(nil, {'action_dispatch.parameter_filter' => ['password'], 'rack.session' => { 'status' => 'ok', 'password' => 'test' }, 'QUERY_STRING' => { 'status' => 'fail' } })
18
+ end
19
+
20
+ it 'returns ok' do
21
+ @rendered_issue.session['status'].must_equal 'ok'
22
+ @rendered_issue.session['password'].must_equal '[FILTERED]'
23
+ end
24
+ end
25
+
15
26
  describe '#title' do
16
27
  before do
17
28
  @exception = Exception.new('message')
@@ -21,7 +32,7 @@ describe 'Rails Issue Renderer' do
21
32
  'action_dispatch.request.path_parameters' => { 'controller' => 'landing', 'action' => 'index' },
22
33
  'action_controller.instance' => controller_instance
23
34
  }
24
- @rendered_issue = PartyFoul::RailsIssueRenderer.new(@exception, env)
35
+ @rendered_issue = PartyFoul::IssueRenderers::Rails.new(@exception, env)
25
36
  end
26
37
 
27
38
  it 'constructs the title with the controller and action' do
@@ -33,7 +33,7 @@ describe 'Party Foul Middleware' do
33
33
 
34
34
  context 'filtering based upon exception' do
35
35
  before do
36
- PartyFoul.ignored_exceptions = ['StandardError']
36
+ PartyFoul.blacklisted_exceptions = ['StandardError']
37
37
  self.stubs(:error_to_raise).returns(StandardError)
38
38
  end
39
39
 
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ describe 'Party Foul Rackless Exception Handler' do
4
+ before do
5
+ PartyFoul.configure do |config|
6
+ config.oauth_token = 'abcdefg1234567890'
7
+ config.owner = 'test_owner'
8
+ config.repo = 'test_repo'
9
+ end
10
+ end
11
+
12
+ describe '#handle' do
13
+ it 'will call run on itself' do
14
+ PartyFoul::RacklessExceptionHandler.any_instance.expects(:run)
15
+ PartyFoul::RacklessExceptionHandler.handle(nil, {})
16
+ end
17
+ end
18
+
19
+ describe '#initialize' do
20
+ it 'should use PartyFoul::IssueRenderers::Rackless for rendering issues' do
21
+ issue_renderer = PartyFoul::RacklessExceptionHandler.new(nil, {}).rendered_issue
22
+ assert_kind_of(PartyFoul::IssueRenderers::Rackless, issue_renderer)
23
+ end
24
+ end
25
+ end
@@ -1,13 +1,16 @@
1
+ require 'bundler/setup'
2
+
1
3
  if defined?(M)
2
4
  require 'minitest/spec'
3
5
  else
4
6
  require 'minitest/autorun'
5
7
  end
6
- require 'rack/test'
7
- require 'mocha/setup'
8
- unless ENV['CI']
8
+ begin
9
9
  require 'debugger'
10
+ rescue LoadError
10
11
  end
12
+ require 'rack/test'
13
+ require 'mocha/setup'
11
14
  require 'party_foul'
12
15
 
13
16
  class MiniTest::Spec
@@ -21,7 +24,7 @@ module MiniTest::Expectations
21
24
  end
22
25
 
23
26
  def clean_up_party
24
- %w{github oauth_token endpoint owner repo ignored_exceptions processor issue_template comment_template filtered_http_headers web_url branch}.each do |attr|
27
+ %w{github oauth_token endpoint owner repo blacklisted_exceptions processor web_url branch}.each do |attr|
25
28
  PartyFoul.send("#{attr}=", nil)
26
29
  end
27
30
  end
@@ -1,28 +1,25 @@
1
1
  PartyFoul.configure do |config|
2
- # the collection of exceptions to be ignored by PartyFoul
2
+ # The collection of exceptions PartyFoul should not be allowed to handle
3
3
  # The constants here *must* be represented as strings
4
- config.ignored_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
5
-
6
- # The names of the HTTP headers to not report
7
- config.filtered_http_headers = ['Cookie']
4
+ config.blacklisted_exceptions = ['ActiveRecord::RecordNotFound', 'ActionController::RoutingError']
8
5
 
9
6
  # The OAuth token for the account that is opening the issues on Github
10
- config.oauth_token = 'test_token'
7
+ config.oauth_token = 'test_token'
11
8
 
12
9
  # The API endpoint for Github. Unless you are hosting a private
13
10
  # instance of Enterprise Github you do not need to include this
14
- config.endpoint = 'http://api.example.com'
11
+ config.endpoint = 'http://api.example.com'
15
12
 
16
13
  # The Web URL for Github. Unless you are hosting a private
17
14
  # instance of Enterprise Github you do not need to include this
18
- config.web_url = 'http://example.com'
15
+ config.web_url = 'http://example.com'
19
16
 
20
17
  # The organization or user that owns the target repository
21
- config.owner = 'test_owner'
18
+ config.owner = 'test_owner'
22
19
 
23
20
  # The repository for this application
24
- config.repo = 'test_repo'
21
+ config.repo = 'test_repo'
25
22
 
26
23
  # The branch for your deployed code
27
- # config.branch = 'master'
24
+ # config.branch = 'master'
28
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: party_foul
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-28 00:00:00.000000000 Z
13
+ date: 2013-02-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: github_api
@@ -28,6 +28,22 @@ dependencies:
28
28
  - - ~>
29
29
  - !ruby/object:Gem::Version
30
30
  version: 0.8.8
31
+ - !ruby/object:Gem::Dependency
32
+ name: io-console
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.3.0
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.3.0
31
47
  - !ruby/object:Gem::Dependency
32
48
  name: actionpack
33
49
  requirement: !ruby/object:Gem::Requirement
@@ -167,12 +183,16 @@ files:
167
183
  - lib/generators/party_foul/install_generator.rb
168
184
  - lib/generators/party_foul/templates/party_foul.rb
169
185
  - lib/party_foul/exception_handler.rb
170
- - lib/party_foul/issue_renderer.rb
186
+ - lib/party_foul/issue_renderers/base.rb
171
187
  - lib/party_foul/issue_renderers/rack.rb
188
+ - lib/party_foul/issue_renderers/rackless.rb
172
189
  - lib/party_foul/issue_renderers/rails.rb
190
+ - lib/party_foul/issue_renderers.rb
173
191
  - lib/party_foul/middleware.rb
192
+ - lib/party_foul/processors/base.rb
174
193
  - lib/party_foul/processors/sync.rb
175
194
  - lib/party_foul/processors.rb
195
+ - lib/party_foul/rackless_exception_handler.rb
176
196
  - lib/party_foul/version.rb
177
197
  - lib/party_foul.rb
178
198
  - Rakefile
@@ -180,10 +200,12 @@ files:
180
200
  - test/generator_test.rb
181
201
  - test/party_foul/configure_test.rb
182
202
  - test/party_foul/exception_handler_test.rb
183
- - test/party_foul/issue_renderer_test.rb
203
+ - test/party_foul/issue_renderers/base_test.rb
184
204
  - test/party_foul/issue_renderers/rack_test.rb
205
+ - test/party_foul/issue_renderers/rackless_test.rb
185
206
  - test/party_foul/issue_renderers/rails_test.rb
186
207
  - test/party_foul/middleware_test.rb
208
+ - test/party_foul/rackless_exception_handler_test.rb
187
209
  - test/test_helper.rb
188
210
  - test/tmp/config/initializers/party_foul.rb
189
211
  homepage: https://github.com/dockyard/party_foul
@@ -200,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
200
222
  version: '0'
201
223
  segments:
202
224
  - 0
203
- hash: -549281873562555121
225
+ hash: -845978866647605957
204
226
  required_rubygems_version: !ruby/object:Gem::Requirement
205
227
  none: false
206
228
  requirements:
@@ -209,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
231
  version: '0'
210
232
  segments:
211
233
  - 0
212
- hash: -549281873562555121
234
+ hash: -845978866647605957
213
235
  requirements: []
214
236
  rubyforge_project:
215
237
  rubygems_version: 1.8.23
@@ -220,9 +242,11 @@ test_files:
220
242
  - test/generator_test.rb
221
243
  - test/party_foul/configure_test.rb
222
244
  - test/party_foul/exception_handler_test.rb
223
- - test/party_foul/issue_renderer_test.rb
245
+ - test/party_foul/issue_renderers/base_test.rb
224
246
  - test/party_foul/issue_renderers/rack_test.rb
247
+ - test/party_foul/issue_renderers/rackless_test.rb
225
248
  - test/party_foul/issue_renderers/rails_test.rb
226
249
  - test/party_foul/middleware_test.rb
250
+ - test/party_foul/rackless_exception_handler_test.rb
227
251
  - test/test_helper.rb
228
252
  - test/tmp/config/initializers/party_foul.rb
@@ -1,139 +0,0 @@
1
- require 'test_helper'
2
- require 'active_support/core_ext/object/blank'
3
- require 'action_dispatch/http/parameter_filter'
4
-
5
- describe 'Party Foul Issue Renderer' do
6
- before do
7
- Time.stubs(:now).returns(Time.new(1970, 1, 1, 0, 0, 0, '-05:00'))
8
- end
9
-
10
- after do
11
- clean_up_party
12
- end
13
-
14
- describe '#body' do
15
- describe 'updating issue body' do
16
- before do
17
- @rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
18
- @rendered_issue.stubs(:exception).returns('Test Exception')
19
- @rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
20
- @rendered_issue.stubs(:stack_trace)
21
- end
22
-
23
- it 'updates count and timestamp' do
24
- body = <<-BODY
25
- <table>
26
- <tr><th>Exception</th><td>Test Exception</td></tr>
27
- <tr><th>Count</th><td>1</td></tr>
28
- <tr><th>Last Occurance</th><td>January 01, 1970 00:00:00 -0500</td></tr>
29
- </table>
30
-
31
- ## Stack Trace
32
- <pre></pre>
33
- Fingerprint: `abcdefg1234567890`
34
- BODY
35
-
36
- Time.stubs(:now).returns(Time.new(1985, 10, 25, 1, 22, 0, '-05:00'))
37
-
38
- expected_body = <<-BODY
39
- <table>
40
- <tr><th>Exception</th><td>Test Exception</td></tr>
41
- <tr><th>Count</th><td>2</td></tr>
42
- <tr><th>Last Occurance</th><td>October 25, 1985 01:22:00 -0500</td></tr>
43
- </table>
44
-
45
- ## Stack Trace
46
- <pre></pre>
47
- Fingerprint: `abcdefg1234567890`
48
- BODY
49
-
50
- @rendered_issue.update_body(body).must_equal expected_body
51
- end
52
- end
53
-
54
- describe 'empty body' do
55
- before do
56
- @rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
57
- @rendered_issue.stubs(:exception).returns('Test Exception')
58
- @rendered_issue.stubs(:fingerprint).returns('abcdefg1234567890')
59
- @rendered_issue.stubs(:stack_trace)
60
- end
61
-
62
- it 'resets body' do
63
- expected_body = <<-BODY
64
- <table>
65
- <tr><th>Exception</th><td>Test Exception</td></tr>
66
- <tr><th>Count</th><td>1</td></tr>
67
- <tr><th>Last Occurance</th><td>January 01, 1970 00:00:00 -0500</td></tr>
68
- </table>
69
-
70
- ## Stack Trace
71
- <pre></pre>
72
- Fingerprint: `abcdefg1234567890`
73
- BODY
74
- @rendered_issue.update_body(nil).must_equal expected_body
75
- end
76
- end
77
- end
78
-
79
- describe '#issue_comment' do
80
- before do
81
- env = {
82
- 'REQUEST_URI' => 'http://example.com/',
83
- 'HTTP_USER_AGENT' => 'test_user_agent',
84
- 'REMOTE_ADDR' => '127.0.0.1',
85
- 'HTTP_HOST' => 'localhost:3000',
86
- 'rack.session' => { :id => 1 }
87
- }
88
- @rendered_issue = PartyFoul::IssueRenderer.new(nil, env)
89
- @rendered_issue.stubs(:params).returns({})
90
- end
91
-
92
- it 'renders a new comment' do
93
- expected_comment = <<-COMMENT
94
- <table>
95
- <tr><th>Occurred at</th><td>January 01, 1970 00:00:00 -0500</td></tr>
96
- <tr><th>Params</th><td><table></table></td></tr>
97
- <tr><th>IP Address</th><td>127.0.0.1</td></tr>
98
- <tr><th>Session</th><td><table><tr><th>id</th><td>1</td></tr></table></td></tr>
99
- <tr><th>HTTP Headers</th><td><table><tr><th>Host</th><td>localhost:3000</td></tr><tr><th>User-Agent</th><td>test_user_agent</td></tr></table></td></tr>
100
- </table>
101
- COMMENT
102
-
103
- @rendered_issue.comment.must_equal expected_comment
104
- end
105
- end
106
-
107
- describe '#compile_template' do
108
- it 'it parses the tags and inserts proper data' do
109
- template = '<span>:data1</span><div>:data2</div>'
110
- @rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
111
- @rendered_issue.stubs(:data1).returns('123')
112
- @rendered_issue.stubs(:data2).returns('abc')
113
- @rendered_issue.compile_template(template).must_equal '<span>123</span><div>abc</div>'
114
- end
115
- end
116
-
117
- describe '#http_headers' do
118
- before do
119
- PartyFoul.filtered_http_headers = ['Cookie']
120
- env = {
121
- 'HTTP_USER_AGENT' => 'test_user_agent',
122
- 'HTTP_COOKIE' => 'test_cookie',
123
- }
124
- @rendered_issue = PartyFoul::IssueRenderer.new(nil, env)
125
- end
126
-
127
- it 'ignored Cookie' do
128
- @rendered_issue.http_headers.must_equal('User-Agent' => 'test_user_agent')
129
- end
130
- end
131
-
132
- describe '#fingerprint' do
133
- it 'SHA1s the title' do
134
- rendered_issue = PartyFoul::IssueRenderer.new(nil, nil)
135
- rendered_issue.stubs(:title).returns('abcdefg1234567890')
136
- rendered_issue.fingerprint.must_equal Digest::SHA1.hexdigest(rendered_issue.title)
137
- end
138
- end
139
- end