contrast-exceptional 0.0.1 → 0.0.6
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/History.txt +6 -0
- data/Manifest +11 -5
- data/README +3 -3
- data/Rakefile +5 -6
- data/exceptional.gemspec +32 -32
- data/init.rb +1 -19
- data/lib/exceptional.rb +12 -223
- data/lib/exceptional/api.rb +108 -0
- data/lib/exceptional/bootstrap.rb +23 -0
- data/lib/exceptional/config.rb +74 -0
- data/lib/exceptional/exception_data.rb +2 -4
- data/lib/exceptional/integration/rails.rb +25 -13
- data/lib/exceptional/log.rb +50 -0
- data/lib/exceptional/remote.rb +75 -0
- data/lib/exceptional/version.rb +1 -1
- data/spec/api_spec.rb +211 -0
- data/spec/bootstrap_spec.rb +58 -0
- data/spec/config_spec.rb +110 -0
- data/spec/exceptional_rescue_from_spec.rb +41 -0
- data/spec/exceptional_spec.rb +16 -58
- data/spec/log_spec.rb +28 -0
- data/spec/remote_spec.rb +137 -0
- data/spec/spec_helper.rb +11 -0
- metadata +43 -25
- data/lib/exceptional/agent/worker.rb +0 -56
- data/lib/exceptional/deployed_environment.rb +0 -86
- data/lib/exceptional/rails.rb +0 -53
- data/spec/deployed_environment_spec.rb +0 -168
- data/spec/worker_spec.rb +0 -21
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module Exceptional
         | 
| 2 | 
            +
              module Bootstrap
         | 
| 3 | 
            +
                
         | 
| 4 | 
            +
                # called from init.rb
         | 
| 5 | 
            +
                def bootstrap(environment, application_root)
         | 
| 6 | 
            +
                  begin
         | 
| 7 | 
            +
                    setup_config(environment, File.join(application_root,"config", "exceptional.yml"))
         | 
| 8 | 
            +
                    setup_log(File.join(application_root, "log"), log_level)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    if enabled?
         | 
| 11 | 
            +
                      if authenticate
         | 
| 12 | 
            +
                        require File.join('exceptional', 'integration', 'rails')
         | 
| 13 | 
            +
                      else
         | 
| 14 | 
            +
                        STDERR.puts "Exceptional plugin not authenticated, check your API Key"
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  rescue Exception => e
         | 
| 18 | 
            +
                    STDERR.puts e
         | 
| 19 | 
            +
                    STDERR.puts "Exceptional Plugin disabled."
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            require 'yaml'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Exceptional
         | 
| 4 | 
            +
              module Config
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                # Defaults for configuration variables
         | 
| 7 | 
            +
                REMOTE_HOST = "getexceptional.com"
         | 
| 8 | 
            +
                REMOTE_PORT = 80
         | 
| 9 | 
            +
                REMOTE_SSL_PORT = 443
         | 
| 10 | 
            +
                SSL = false
         | 
| 11 | 
            +
                LOG_LEVEL = 'info'
         | 
| 12 | 
            +
                LOG_PATH = nil
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                class ConfigurationException < StandardError; end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                attr_reader :api_key
         | 
| 17 | 
            +
                attr_writer :ssl_enabled, :remote_host, :remote_port, :api_key
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def setup_config(environment, config_file)
         | 
| 20 | 
            +
                  begin
         | 
| 21 | 
            +
                    config = YAML::load(File.open(config_file))[environment]
         | 
| 22 | 
            +
                    @api_key = config['api-key'] unless config['api-key'].nil?
         | 
| 23 | 
            +
                    @ssl_enabled = config['ssl'] unless config['ssl'].nil?
         | 
| 24 | 
            +
                    @log_level = config['log-level'] unless config['log-level'].nil?
         | 
| 25 | 
            +
                    @enabled = config['enabled'] unless config['enabled'].nil?
         | 
| 26 | 
            +
                    @remote_port = config['remote-port'].to_i unless config['remote-port'].nil?
         | 
| 27 | 
            +
                    @remote_host = config['remote-host'] unless config['remote-host'].nil?
         | 
| 28 | 
            +
                    @applicaton_root = application_root
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    log_config_info
         | 
| 31 | 
            +
                  rescue Exception => e
         | 
| 32 | 
            +
                    raise ConfigurationException.new("Unable to load configuration #{config_file} for environment #{environment} : #{e.message}")
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def application_root
         | 
| 37 | 
            +
                  @applicaton_root || (File.dirname(__FILE__) + '/../..')
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def remote_host
         | 
| 41 | 
            +
                  @remote_host || REMOTE_HOST
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def remote_port
         | 
| 45 | 
            +
                  @remote_port || default_port
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def log_level
         | 
| 49 | 
            +
                  @log_level || LOG_LEVEL
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def default_port
         | 
| 53 | 
            +
                  ssl_enabled? ? REMOTE_SSL_PORT : REMOTE_PORT
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def ssl_enabled?
         | 
| 57 | 
            +
                  @ssl_enabled || SSL
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def enabled?
         | 
| 61 | 
            +
                  @enabled || false
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def valid_api_key?
         | 
| 65 | 
            +
                  @api_key && @api_key.length == 40 ? true : false
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def log_config_info
         | 
| 69 | 
            +
                  Exceptional.to_log('debug', "API Key: #{api_key}")
         | 
| 70 | 
            +
                  Exceptional.to_log('debug', "Remote Host: #{remote_host}:#{remote_port}")
         | 
| 71 | 
            +
                  Exceptional.to_log('debug', "Log level: #{log_level}")
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -32,15 +32,13 @@ module Exceptional | |
| 32 32 | 
             
                  hash = {}
         | 
| 33 33 | 
             
                  ::ATTRS.each do |attribute|
         | 
| 34 34 | 
             
                    value = send(attribute)
         | 
| 35 | 
            -
                    hash[attribute] = value unless (value.nil? || value.empty?)
         | 
| 35 | 
            +
                    hash[attribute] = value unless (value.nil? || value.empty? || attribute.is_a?(TCPSocket) || attribute.is_a?(TCPServer)) 
         | 
| 36 36 | 
             
                  end
         | 
| 37 37 | 
             
                  hash
         | 
| 38 38 | 
             
                end
         | 
| 39 39 |  | 
| 40 40 | 
             
                def to_json
         | 
| 41 41 | 
             
                  self.to_hash.to_json
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
                
         | 
| 42 | 
            +
                end    
         | 
| 44 43 | 
             
              end
         | 
| 45 | 
            -
              
         | 
| 46 44 | 
             
            end
         | 
| @@ -1,20 +1,32 @@ | |
| 1 | 
            +
            if defined? ActiveSupport
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              # Hack to force Rails version prior to 2.0 to use quoted JSON as per the JSON standard... (TODO: could be cleaner!)
         | 
| 4 | 
            +
              if (defined?(ActiveSupport::JSON) && ActiveSupport::JSON.respond_to?(:unquote_hash_key_identifiers))
         | 
| 5 | 
            +
                ActiveSupport::JSON.unquote_hash_key_identifiers = false 
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            if defined? ActionController
         | 
| 2 11 |  | 
| 3 | 
            -
            module ActionController
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                 | 
| 6 | 
            -
                  
         | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 12 | 
            +
              module ActionController
         | 
| 13 | 
            +
                class Base
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                  def rescue_action_with_exceptional(exception)
         | 
| 16 | 
            +
                    # TODO potentially hook onto rescue_without_handler if it exists? would negate need to check handler_for_rescue every time.
         | 
| 17 | 
            +
                    # if there's handler defined with rescue_from() do not call Exceptional
         | 
| 18 | 
            +
                    if !(respond_to?(:handler_for_rescue) && handler_for_rescue(exception))
         | 
| 19 | 
            +
                      params_to_send = (respond_to? :filter_parameters) ? filter_parameters(params) : params
         | 
| 20 | 
            +
                      Exceptional.handle(exception, self, request, params_to_send)
         | 
| 21 | 
            +
                    end
         | 
| 10 22 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 23 | 
            +
                    rescue_action_without_exceptional exception
         | 
| 24 | 
            +
                  end
         | 
| 13 25 |  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 26 | 
            +
                  alias_method :rescue_action_without_exceptional, :rescue_action
         | 
| 27 | 
            +
                  alias_method :rescue_action, :rescue_action_with_exceptional
         | 
| 28 | 
            +
                  protected :rescue_action
         | 
| 29 | 
            +
                end
         | 
| 17 30 | 
             
              end
         | 
| 18 | 
            -
            end
         | 
| 19 31 |  | 
| 20 32 | 
             
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require 'logger'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Exceptional
         | 
| 4 | 
            +
              module Log
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                attr_reader :log
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def setup_log(log_dir, log_level = Logger::INFO)
         | 
| 9 | 
            +
                  begin
         | 
| 10 | 
            +
                    Dir.mkdir(log_dir) unless File.directory?(log_dir)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    
         | 
| 13 | 
            +
                    log_path = File.join(log_dir, "/exceptional.log")
         | 
| 14 | 
            +
                    log = Logger.new log_path
         | 
| 15 | 
            +
                    
         | 
| 16 | 
            +
                    log.level = log_level
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    allowed_log_levels = ['debug', 'info', 'warn', 'error', 'fatal']
         | 
| 19 | 
            +
                    if log_level && allowed_log_levels.include?(log_level)
         | 
| 20 | 
            +
                      log.level = eval("Logger::#{log_level.upcase}")
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    @log = log
         | 
| 24 | 
            +
                  rescue Exception => e
         | 
| 25 | 
            +
                    raise Exceptional::Config::ConfigurationException.new("Unable to create log file #{log_path} #{e.message}")
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def log!(msg, level = 'info')
         | 
| 30 | 
            +
                  to_log level, msg
         | 
| 31 | 
            +
                  to_stderr msg
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def to_stderr(msg)
         | 
| 35 | 
            +
                  STDERR.puts format_log_message(msg)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                protected
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def to_log(level, msg)
         | 
| 41 | 
            +
                  @log.send level, msg if @log
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                private
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def format_log_message(msg)
         | 
| 47 | 
            +
                  "** [Exceptional] " + msg
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            require 'zlib'
         | 
| 2 | 
            +
            require 'cgi'
         | 
| 3 | 
            +
            require 'net/http'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Exceptional
         | 
| 6 | 
            +
              module Remote
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class RemoteException < StandardError; end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                ::PROTOCOL_VERSION = 3
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # authenticate with getexceptional.com
         | 
| 13 | 
            +
                # returns true if the configured api_key is registered and can send data
         | 
| 14 | 
            +
                # otherwise false
         | 
| 15 | 
            +
                def authenticate
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  return @authenticated if @authenticated
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  if Exceptional.api_key.nil?
         | 
| 20 | 
            +
                    raise Exceptional::Config::ConfigurationException.new("API Key must be configured")
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  begin
         | 
| 24 | 
            +
                    # TODO No data required to authenticate, send a nil string? hacky
         | 
| 25 | 
            +
                    # TODO should retry if a http connection failed
         | 
| 26 | 
            +
                    authenticated = call_remote(:authenticate, "")
         | 
| 27 | 
            +
                    
         | 
| 28 | 
            +
                    @authenticated = authenticated =~ /true/ ? true : false
         | 
| 29 | 
            +
                  rescue
         | 
| 30 | 
            +
                    @authenticated = false
         | 
| 31 | 
            +
                  ensure
         | 
| 32 | 
            +
                    return @authenticated
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def authenticated?
         | 
| 37 | 
            +
                  @authenticated || false
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def post_exception(data)
         | 
| 41 | 
            +
                  if !authenticated?
         | 
| 42 | 
            +
                    authenticate
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  call_remote(:errors, data)
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                protected
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def call_remote(method, data)
         | 
| 51 | 
            +
                  begin
         | 
| 52 | 
            +
                    http = Net::HTTP.new(Exceptional.remote_host, Exceptional.remote_port)
         | 
| 53 | 
            +
                    http.use_ssl = true if Exceptional.ssl_enabled?
         | 
| 54 | 
            +
                    uri = "/#{method.to_s}?&api_key=#{Exceptional.api_key}&protocol_version=#{::PROTOCOL_VERSION}"
         | 
| 55 | 
            +
                    headers = method.to_s == 'errors' ? { 'Content-Type' => 'application/x-gzip', 'Accept' => 'application/x-gzip' } : {}
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    compressed_data = CGI::escape(Zlib::Deflate.deflate(data, Zlib::BEST_SPEED))
         | 
| 58 | 
            +
                    response = http.start do |http|
         | 
| 59 | 
            +
                      http.post(uri, compressed_data, headers)
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    if response.kind_of? Net::HTTPSuccess
         | 
| 63 | 
            +
                      return response.body
         | 
| 64 | 
            +
                    else
         | 
| 65 | 
            +
                      raise RemoteException.new("#{response.code}: #{response.message}")
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  rescue Exception => e
         | 
| 69 | 
            +
                    Exceptional.log! "Error contacting Exceptional: #{e}", 'info'
         | 
| 70 | 
            +
                    Exceptional.log! e.backtrace.join("\n"), 'debug'
         | 
| 71 | 
            +
                    raise e
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
    
        data/lib/exceptional/version.rb
    CHANGED
    
    
    
        data/spec/api_spec.rb
    ADDED
    
    | @@ -0,0 +1,211 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe Exceptional::Api do
         | 
| 5 | 
            +
             | 
| 6 | 
            +
             | 
| 7 | 
            +
              describe "with no configuration" do
         | 
| 8 | 
            +
                before(:each) do
         | 
| 9 | 
            +
                Exceptional.stub!(:to_stderr) # Don't print error when testing
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                after(:each) do
         | 
| 13 | 
            +
                  Exceptional.api_key= nil
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                it "should connect to getexceptional.com by default" do
         | 
| 17 | 
            +
                  Exceptional.remote_host.should == "getexceptional.com"
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                it "should connect to port 80 by default" do
         | 
| 21 | 
            +
                  Exceptional.remote_port.should == 80
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                it "should parse exception into exception data object" do
         | 
| 25 | 
            +
                  exception = mock(Exception, :message => "Something bad has happened",
         | 
| 26 | 
            +
                  :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"])
         | 
| 27 | 
            +
                  exception_data = Exceptional.parse(exception)
         | 
| 28 | 
            +
                  exception_data.kind_of?(Exceptional::ExceptionData).should be_true
         | 
| 29 | 
            +
                  exception_data.exception_message.should == exception.message
         | 
| 30 | 
            +
                  exception_data.exception_backtrace.should == exception.backtrace
         | 
| 31 | 
            +
                  exception_data.exception_class.should == exception.class.to_s
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it "should post exception" do
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  exception_data = mock(Exceptional::ExceptionData,
         | 
| 39 | 
            +
                  :message => "Something bad has happened",
         | 
| 40 | 
            +
                  :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"],
         | 
| 41 | 
            +
                  :class => Exception, :to_hash => { :message => "Something bad has happened" })
         | 
| 42 | 
            +
                  Exceptional.api_key = "TEST_API_KEY"
         | 
| 43 | 
            +
                  Exceptional.should_receive(:authenticate).once.and_return(true)
         | 
| 44 | 
            +
                  Exceptional.should_receive(:call_remote, :with => [:errors, exception_data]).once
         | 
| 45 | 
            +
                  Exceptional.post(exception_data)
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                it "should catch exception" do
         | 
| 50 | 
            +
                  exception = mock(Exception, :message => "Something bad has happened",
         | 
| 51 | 
            +
                  :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"])
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  exception_data = mock(Exceptional::ExceptionData,
         | 
| 54 | 
            +
                  :message => "Something bad has happened",
         | 
| 55 | 
            +
                  :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"],
         | 
| 56 | 
            +
                  :class => Exception, :to_hash => { :message => "Something bad has happened" })
         | 
| 57 | 
            +
                  exception_data.should_receive(:controller_name=).with(File.basename($0))
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  Exceptional.should_receive(:parse, :with => [exception]).and_return(exception_data)
         | 
| 60 | 
            +
                  Exceptional.should_receive(:post, :with => [exception_data])
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  Exceptional.catch(exception)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                it "should raise a license exception if api key is not set" do
         | 
| 66 | 
            +
                  exception_data = mock(Exceptional::ExceptionData,
         | 
| 67 | 
            +
                  :message => "Something bad has happened",
         | 
| 68 | 
            +
                  :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"],
         | 
| 69 | 
            +
                  :class => Exception,
         | 
| 70 | 
            +
                  :to_hash => { :message => "Something bad has happened" })
         | 
| 71 | 
            +
                  Exceptional.api_key.should == nil
         | 
| 72 | 
            +
                  lambda { Exceptional.post(exception_data) }.should raise_error(Exceptional::Config::ConfigurationException)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              describe "rescue" do
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                it "should send exception data onto catch" do
         | 
| 79 | 
            +
                  Exceptional.should_receive(:catch)
         | 
| 80 | 
            +
                  lambda{ Exceptional.rescue do
         | 
| 81 | 
            +
                    raise IOError
         | 
| 82 | 
            +
                  end}.should raise_error(IOError)
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              describe "handle" do
         | 
| 88 | 
            +
                before(:each) do
         | 
| 89 | 
            +
                Exceptional.stub!(:to_stderr) # Don't print error when testing
         | 
| 90 | 
            +
                Exceptional.stub!(:log!) # Don't even attempt to log
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                it "should send exception data onto post" do
         | 
| 94 | 
            +
                  exception = mock(Exception, :message => "Something bad has happened",
         | 
| 95 | 
            +
                  :backtrace => "/app/controllers/buggy_controller.rb:29:in `index'")
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  controller = mock("controller", :controller_name => "Test Controller Name", :action_name => "Test Action Name")
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  class SessionHelper
         | 
| 100 | 
            +
                    def initialize
         | 
| 101 | 
            +
                      @some_var = 1
         | 
| 102 | 
            +
                      @cgi_var = 2
         | 
| 103 | 
            +
                      @x_db = 3
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  request = mock("request", :env => {"key1" => "val1"}, :protocol => "http", :host => "getexceptional.com", :request_uri => "/path/to/resource", :session => SessionHelper.new)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  Exceptional.should_receive(:post_exception).once
         | 
| 110 | 
            +
                  Exceptional.handle(exception, controller, request, {:clients => {:name => "bar"}})
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              describe "with helper methods" do
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                it "safe_environment() should delete all rack related stuff from environment" do
         | 
| 117 | 
            +
                  request = mock(request, :env => { 'rack_var' => 'value', 'non_ack' => 'value2' })
         | 
| 118 | 
            +
                  Exceptional.send(:safe_environment, request).should == { 'non_ack' => 'value2' }
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                it "safe_environment() should handle array type parameters" do
         | 
| 122 | 
            +
                  
         | 
| 123 | 
            +
                  request = mock(request, :env => { 
         | 
| 124 | 
            +
                      'string_array_var' => ['value', 'another value'], 
         | 
| 125 | 
            +
                      'bool_array_var' => [false, false, true],
         | 
| 126 | 
            +
                      'numb_array_var' => [3,2,1],
         | 
| 127 | 
            +
                      'nil_array_var' => [nil, nil],
         | 
| 128 | 
            +
                      'non_ack' => 'value2' }
         | 
| 129 | 
            +
                      )
         | 
| 130 | 
            +
                  Exceptional.send(:safe_environment, request).should == { 
         | 
| 131 | 
            +
                    'string_array_var' => ['value', 'another value'], 
         | 
| 132 | 
            +
                    'bool_array_var' => [false, false, true],
         | 
| 133 | 
            +
                    'numb_array_var' => [3,2,1],
         | 
| 134 | 
            +
                    'nil_array_var' => [nil, nil],
         | 
| 135 | 
            +
                    'non_ack' => 'value2' }
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                it "safe_session() should handle array type parameters" do
         | 
| 140 | 
            +
                  mock_session = mock("session")
         | 
| 141 | 
            +
                  mock_session.should_receive(:instance_variables).and_return(['var1', 'var2'])
         | 
| 142 | 
            +
                  mock_session.should_receive(:instance_variable_get).with('var1').and_return(['value', 'another value'])
         | 
| 143 | 
            +
                  mock_session.should_receive(:instance_variable_get).with('var2').and_return('value2')
         | 
| 144 | 
            +
                  Exceptional.send(:safe_session, mock_session).should == { 'var1' => ['value', 'another value'], 'var2' => 'value2' }
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
             | 
| 148 | 
            +
                it "safe_session() should filter all /db/, /cgi/ variables and sub @ for blank" do
         | 
| 149 | 
            +
                  class SessionHelper
         | 
| 150 | 
            +
                    def initialize
         | 
| 151 | 
            +
                      @some_var = 1
         | 
| 152 | 
            +
                      @cgi_var = 2
         | 
| 153 | 
            +
                      @x_db = 3
         | 
| 154 | 
            +
                    end
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                  session = SessionHelper.new
         | 
| 158 | 
            +
                  Exceptional.send(:safe_session, session).should == { 'some_var' => 1 }
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                it "sanitize_hash() should sanitize cyclic problem for to_json" do
         | 
| 162 | 
            +
                  class MyClass
         | 
| 163 | 
            +
                    def initialize
         | 
| 164 | 
            +
                      @test = self
         | 
| 165 | 
            +
                    end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                    def to_hash
         | 
| 168 | 
            +
                      { :test => self }
         | 
| 169 | 
            +
                    end
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
                  my_class = MyClass.new
         | 
| 172 | 
            +
                  
         | 
| 173 | 
            +
                  lambda { my_class.to_json }.should raise_error(ActiveSupport::JSON::CircularReferenceError)
         | 
| 174 | 
            +
                  Exceptional.send(:sanitize_hash, my_class.to_hash).to_json.should == "{}"
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
                
         | 
| 177 | 
            +
                it "sanitize_hash() should sanitize cyclic problem for to_json passing hash" do
         | 
| 178 | 
            +
                  class MyClass
         | 
| 179 | 
            +
                    def initialize
         | 
| 180 | 
            +
                      @test = self
         | 
| 181 | 
            +
                    end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                    def to_hash
         | 
| 184 | 
            +
                      { :test => self }
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
                  my_class = MyClass.new
         | 
| 188 | 
            +
                  
         | 
| 189 | 
            +
                  
         | 
| 190 | 
            +
                  lambda { my_class.to_json }.should raise_error(ActiveSupport::JSON::CircularReferenceError)
         | 
| 191 | 
            +
                  Exceptional.send(:sanitize_hash, {'hkey' => my_class}).to_json.should == "{}"
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
                
         | 
| 194 | 
            +
                it "sanitize_hash() should sanitize cyclic problem for to_json passing hash mult params" do
         | 
| 195 | 
            +
                  class MyClass
         | 
| 196 | 
            +
                    def initialize
         | 
| 197 | 
            +
                      @test = self
         | 
| 198 | 
            +
                    end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                    def to_hash
         | 
| 201 | 
            +
                      { :test => self }
         | 
| 202 | 
            +
                    end
         | 
| 203 | 
            +
                  end
         | 
| 204 | 
            +
                  my_class = MyClass.new
         | 
| 205 | 
            +
                  
         | 
| 206 | 
            +
                  
         | 
| 207 | 
            +
                  lambda { my_class.to_json }.should raise_error(ActiveSupport::JSON::CircularReferenceError)
         | 
| 208 | 
            +
                  Exceptional.send(:sanitize_hash, {'hkey' => my_class, 'ruby' => 'tuesday'}).to_json.should == "{\"ruby\": \"tuesday\"}"
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
              end
         | 
| 211 | 
            +
            end
         |