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,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Exceptional::Bootstrap do
|
5
|
+
|
6
|
+
|
7
|
+
describe "setup" do
|
8
|
+
|
9
|
+
TEST_ENVIRONMENT= "development"
|
10
|
+
|
11
|
+
it "should initialize the config and log" do
|
12
|
+
Exceptional.should_receive(:setup_config)
|
13
|
+
Exceptional.should_receive(:setup_log)
|
14
|
+
|
15
|
+
Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should authenticate if enabled" do
|
19
|
+
Exceptional.should_receive(:setup_config)
|
20
|
+
Exceptional.should_receive(:setup_log)
|
21
|
+
Exceptional.should_receive(:enabled?).and_return(true)
|
22
|
+
Exceptional.should_receive(:authenticate).and_return(true)
|
23
|
+
STDERR.should_not_receive(:puts) #Should be no errors to report
|
24
|
+
|
25
|
+
Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not authenticate if not enabled" do
|
29
|
+
Exceptional.should_receive(:setup_config)
|
30
|
+
Exceptional.should_receive(:setup_log)
|
31
|
+
Exceptional.should_receive(:enabled?).and_return(false)
|
32
|
+
Exceptional.should_not_receive(:authenticate)
|
33
|
+
STDERR.should_not_receive(:puts) # Will silently not enable itself
|
34
|
+
|
35
|
+
|
36
|
+
Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should report to STDERR if authentication fails" do
|
40
|
+
Exceptional.should_receive(:setup_config)
|
41
|
+
Exceptional.should_receive(:setup_log)
|
42
|
+
Exceptional.should_receive(:enabled?).and_return(true)
|
43
|
+
Exceptional.should_receive(:authenticate).and_return(false)
|
44
|
+
STDERR.should_receive(:puts) #Should be no errors to report
|
45
|
+
|
46
|
+
Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should report to STDERR if error during config initialization" do
|
50
|
+
Exceptional.should_receive(:setup_config).and_raise(Exceptional::Config::ConfigurationException)
|
51
|
+
Exceptional.should_not_receive(:setup_log)
|
52
|
+
Exceptional.should_not_receive(:authenticate).and_return(false)
|
53
|
+
STDERR.should_receive(:puts).twice() #Should be no errors to report
|
54
|
+
|
55
|
+
Exceptional.bootstrap(TEST_ENVIRONMENT, File.dirname(__FILE__))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Exceptional::Config do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
|
8
|
+
def Exceptional.reset_state
|
9
|
+
@api_key = nil
|
10
|
+
@ssl_enabled = nil
|
11
|
+
@log_level = nil
|
12
|
+
@enabled = nil
|
13
|
+
@remote_port = nil
|
14
|
+
@remote_host = nil
|
15
|
+
@applicaton_root = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:each) do
|
21
|
+
Exceptional.reset_state
|
22
|
+
end
|
23
|
+
|
24
|
+
before(:each) do
|
25
|
+
Exceptional.stub!(:log!) # Don't even attempt to log
|
26
|
+
Exceptional.stub!(:to_log)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "default configuration" do
|
30
|
+
|
31
|
+
it "should use port 80 by default if ssl not enabled" do
|
32
|
+
Exceptional.ssl_enabled?.should be_false
|
33
|
+
Exceptional.remote_port.should == 80
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should use port 443 if ssl enabled" do
|
37
|
+
Exceptional.ssl_enabled= true
|
38
|
+
Exceptional.remote_port.should == 443
|
39
|
+
Exceptional.ssl_enabled= false
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should use log level of info by default" do
|
43
|
+
Exceptional.log_level.should == "info"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not be enabled by default" do
|
47
|
+
Exceptional.enabled?.should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should overwrite default host" do
|
51
|
+
Exceptional.remote_host.should == "getexceptional.com"
|
52
|
+
Exceptional.remote_host = "localhost"
|
53
|
+
Exceptional.remote_host.should == "localhost"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should overwrite default port" do
|
57
|
+
Exceptional.remote_port.should == 80
|
58
|
+
|
59
|
+
Exceptional.remote_port = 3000
|
60
|
+
Exceptional.remote_port.should == 3000
|
61
|
+
Exceptional.remote_port = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
it "api_key should by default be in-valid" do
|
65
|
+
Exceptional.valid_api_key?.should be_false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "load config" do
|
70
|
+
|
71
|
+
it "error during config file loading raises configuration exception" do
|
72
|
+
File.should_receive(:open).once.and_raise(IOError)
|
73
|
+
|
74
|
+
lambda{Exceptional.setup_config("development", File.dirname(__FILE__))}.should raise_error(Exceptional::Config::ConfigurationException)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "is enabled for production environment" do
|
78
|
+
Exceptional.enabled?.should be_false
|
79
|
+
|
80
|
+
Exceptional.setup_config "production", File.join(File.dirname(__FILE__), "/../exceptional.yml")
|
81
|
+
Exceptional.enabled?.should be_true
|
82
|
+
end
|
83
|
+
|
84
|
+
it "is enabled by default for production and staging environments" do
|
85
|
+
Exceptional.enabled?.should be_false
|
86
|
+
|
87
|
+
Exceptional.setup_config "production", File.join(File.dirname(__FILE__), "/../exceptional.yml")
|
88
|
+
Exceptional.enabled?.should be_true
|
89
|
+
|
90
|
+
Exceptional.reset_state
|
91
|
+
Exceptional.enabled?.should be_false
|
92
|
+
|
93
|
+
Exceptional.setup_config "staging", File.join(File.dirname(__FILE__), "/../exceptional.yml")
|
94
|
+
Exceptional.enabled?.should be_true
|
95
|
+
end
|
96
|
+
|
97
|
+
it "is disabled by default for development & test environments" do
|
98
|
+
Exceptional.enabled?.should be_false
|
99
|
+
|
100
|
+
Exceptional.setup_config "development", File.join(File.dirname(__FILE__), "/../exceptional.yml")
|
101
|
+
Exceptional.enabled?.should be_false
|
102
|
+
|
103
|
+
Exceptional.reset_state
|
104
|
+
Exceptional.enabled?.should be_false
|
105
|
+
|
106
|
+
Exceptional.setup_config "test", File.join(File.dirname(__FILE__), "/../exceptional.yml")
|
107
|
+
Exceptional.enabled?.should be_false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'action_controller'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'exceptional', 'integration', 'rails')
|
4
|
+
|
5
|
+
class MyException < Exception; end
|
6
|
+
class SpecialException < Exception; end
|
7
|
+
class RescueFromController < ActionController::Base
|
8
|
+
rescue_from MyException, :with => :my_handler
|
9
|
+
|
10
|
+
def my_handler
|
11
|
+
return 'test'
|
12
|
+
end
|
13
|
+
|
14
|
+
def my_action
|
15
|
+
raise MyException
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "Exceptional with rescue_from() support" do
|
21
|
+
before(:each) do
|
22
|
+
@controller = RescueFromController.new
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should not call Exceptional" do
|
26
|
+
@controller.should_receive(:rescue_action_without_exceptional).and_return(true)
|
27
|
+
if Gem::Requirement.create(">=2.2.0").satisfied_by?(Gem.loaded_specs['rails'].version)
|
28
|
+
Exceptional.should_not_receive(:handle)
|
29
|
+
else
|
30
|
+
Exceptional.should_receive(:handle)
|
31
|
+
end
|
32
|
+
@controller.send(:rescue_action, MyException.new("test")).should == true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should call Exceptional" do
|
36
|
+
Exceptional.should_receive(:handle)
|
37
|
+
@controller.should_receive(:rescue_action_without_exceptional).and_return(true)
|
38
|
+
@controller.send(:rescue_action, SpecialException.new("test")).should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/exceptional_spec.rb
CHANGED
@@ -1,67 +1,25 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
|
+
|
3
4
|
describe Exceptional do
|
4
|
-
|
5
|
+
|
5
6
|
describe "with no configuration" do
|
6
|
-
|
7
|
-
Exceptional.
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should connect to port 80 by default" do
|
11
|
-
Exceptional.remote_port.should == 80
|
7
|
+
before(:each) do
|
8
|
+
Exceptional.stub!(:to_stderr) # Don't print error when testing
|
12
9
|
end
|
13
|
-
|
14
|
-
it "should
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should post exception" do
|
24
|
-
exception_data = mock(Exceptional::ExceptionData, :message => "Something bad has happened", :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"], :class => Exception)
|
25
|
-
Exceptional.should_receive(:call_remote, :with => [:errors, exception_data])
|
26
|
-
Exceptional.post(exception_data)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should catch exception" do
|
30
|
-
exception = mock(Exception, :message => "Something bad has happened", :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"])
|
31
|
-
exception_data = mock(Exceptional::ExceptionData, :message => "Something bad has happened", :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"], :class => Exception)
|
32
|
-
Exceptional.should_receive(:parse, :with => [exception]).and_return(exception_data)
|
33
|
-
Exceptional.should_receive(:post, :with => [exception_data])
|
34
|
-
Exceptional.catch(exception)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should raise a license exception if api key is not set" do
|
38
|
-
exception_data = mock(Exceptional::ExceptionData, :message => "Something bad has happened", :backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"], :class => Exception)
|
10
|
+
|
11
|
+
it "should raise a remoting exception if not authenticated" do
|
12
|
+
exception_data = mock(Exceptional::ExceptionData,
|
13
|
+
:message => "Something bad has happened",
|
14
|
+
:backtrace => ["/app/controllers/buggy_controller.rb:29:in `index'"],
|
15
|
+
:class => Exception,
|
16
|
+
:to_hash => { :message => "Something bad has happened" })
|
17
|
+
|
39
18
|
Exceptional.api_key.should == nil
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "with a custom host" do
|
46
|
-
|
47
|
-
it "should overwrite default host" do
|
48
|
-
Exceptional.remote_host = "localhost"
|
49
|
-
Exceptional.remote_host.should == "localhost"
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should overwrite default port" do
|
53
|
-
Exceptional.remote_port = 3000
|
54
|
-
Exceptional.remote_port.should == 3000
|
55
|
-
Exceptional.remote_port = nil
|
19
|
+
Exceptional.should_receive(:authenticated?).once.and_return(false)
|
20
|
+
|
21
|
+
lambda { Exceptional.post_exception(exception_data) }.should raise_error(Exceptional::Config::ConfigurationException)
|
56
22
|
end
|
57
23
|
end
|
58
24
|
|
59
|
-
|
60
|
-
|
61
|
-
it "should connect to port 443" do
|
62
|
-
Exceptional.ssl_enabled = true
|
63
|
-
Exceptional.remote_port.should == 443
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
25
|
+
end
|
data/spec/log_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Exceptional::Log do
|
4
|
+
|
5
|
+
TEST_LOG_MESSAGE = "Test-log-message"
|
6
|
+
|
7
|
+
it "uninitialized should only log to STDERR" do
|
8
|
+
|
9
|
+
STDERR.should_receive(:puts)
|
10
|
+
Logger.should_not_receive(:send)
|
11
|
+
Exceptional.log! TEST_LOG_MESSAGE
|
12
|
+
end
|
13
|
+
|
14
|
+
it "initialized should log to both STDERR and log file" do
|
15
|
+
|
16
|
+
mock_log = mock("log")
|
17
|
+
mock_log.should_receive(:level=)
|
18
|
+
|
19
|
+
Logger.should_receive(:new).and_return(mock_log)
|
20
|
+
|
21
|
+
Exceptional.setup_log File.dirname(File.join(File.dirname(__FILE__), ".."))
|
22
|
+
|
23
|
+
Exceptional.log.should_receive(:send).with("info", TEST_LOG_MESSAGE)
|
24
|
+
STDERR.should_receive(:puts)
|
25
|
+
|
26
|
+
Exceptional.log! TEST_LOG_MESSAGE
|
27
|
+
end
|
28
|
+
end
|
data/spec/remote_spec.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
describe Exceptional::Remote do
|
5
|
+
|
6
|
+
TEST_API_KEY = "TEST_API_KEY"
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
def Exceptional.reset_state
|
10
|
+
@api_key = nil
|
11
|
+
@ssl_enabled = nil
|
12
|
+
@log_level = nil
|
13
|
+
@enabled = nil
|
14
|
+
@remote_port = nil
|
15
|
+
@remote_host = nil
|
16
|
+
@applicaton_root = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def Exceptional.reset_authentication
|
20
|
+
@authenticated = false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:each) do
|
25
|
+
Exceptional.reset_state
|
26
|
+
Exceptional.reset_authentication
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "authentication" do
|
30
|
+
|
31
|
+
it "should not be authenticated if API authentication unsuccessful" do
|
32
|
+
Exceptional.api_key = TEST_API_KEY
|
33
|
+
|
34
|
+
Exceptional.authenticated?.should be_false
|
35
|
+
Exceptional.should_receive(:call_remote, {:method => "authenticate", :data => ""}).once.and_return("false")
|
36
|
+
Exceptional.authenticate.should be_false
|
37
|
+
Exceptional.authenticated?.should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not be authenticated if error during API authenticate" do
|
41
|
+
Exceptional.api_key = TEST_API_KEY
|
42
|
+
|
43
|
+
Exceptional.authenticated?.should be_false
|
44
|
+
Exceptional.should_receive(:call_remote, {:method => "authenticate", :data => ""}).once.and_raise(IOError)
|
45
|
+
|
46
|
+
Exceptional.authenticate.should be_false
|
47
|
+
Exceptional.authenticated?.should be_false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not re-authenticate subsequently if 1 successful " do
|
51
|
+
Exceptional.api_key = TEST_API_KEY
|
52
|
+
|
53
|
+
Exceptional.authenticated?.should be_false
|
54
|
+
Exceptional.should_receive(:call_remote, {:method => "authenticate", :data => ""}).once.and_return("true")
|
55
|
+
# If authentication is successful, authenticate called only once
|
56
|
+
|
57
|
+
Exceptional.authenticate.should be_true
|
58
|
+
Exceptional.authenticated?.should be_true
|
59
|
+
|
60
|
+
Exceptional.authenticate.should be_true
|
61
|
+
Exceptional.authenticated?.should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "with no API Key set throws Configuration Exception" do
|
65
|
+
Exceptional.authenticated?.should be_false
|
66
|
+
|
67
|
+
lambda {Exceptional.authenticate}.should raise_error(Exceptional::Config::ConfigurationException)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "sending data " do
|
72
|
+
|
73
|
+
it "should return response body if successful" do
|
74
|
+
|
75
|
+
OK_RESPONSE_BODY = "OK-RESP-BODY"
|
76
|
+
|
77
|
+
Exceptional.api_key = TEST_API_KEY
|
78
|
+
Exceptional.authenticated?.should be_false
|
79
|
+
|
80
|
+
Exceptional.should_receive(:authenticated?).once.and_return(true)
|
81
|
+
|
82
|
+
mock_http = mock(Net::HTTP)
|
83
|
+
Net::HTTP.should_receive(:new).with("getexceptional.com", 80).once.and_return(mock_http)
|
84
|
+
|
85
|
+
mock_http_response= mock(Net::HTTPSuccess)
|
86
|
+
mock_http_response.should_receive(:kind_of?).with(Net::HTTPSuccess).once.and_return(true)
|
87
|
+
mock_http_response.should_receive(:body).once.and_return(OK_RESPONSE_BODY)
|
88
|
+
|
89
|
+
mock_http.should_receive(:start).once.and_return(mock_http_response)
|
90
|
+
|
91
|
+
Exceptional.post_exception("data").should == OK_RESPONSE_BODY
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should raise error if network problem during sending exception" do
|
95
|
+
|
96
|
+
Exceptional.api_key = TEST_API_KEY
|
97
|
+
Exceptional.authenticated?.should be_false
|
98
|
+
|
99
|
+
Exceptional.should_receive(:authenticated?).once.and_return(true)
|
100
|
+
|
101
|
+
mock_http = mock(Net::HTTP)
|
102
|
+
Net::HTTP.should_receive(:new).with("getexceptional.com", 80).once.and_return(mock_http)
|
103
|
+
|
104
|
+
mock_http_response= mock(Net::HTTPSuccess)
|
105
|
+
|
106
|
+
mock_http.should_receive(:start).once.and_raise(IOError)
|
107
|
+
|
108
|
+
#surpress the logging of the exception
|
109
|
+
Exceptional.should_receive(:log!).twice
|
110
|
+
|
111
|
+
lambda{Exceptional.post_exception("data")}.should raise_error(IOError)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should raise Exception if sending exception unsuccessful" do
|
115
|
+
|
116
|
+
Exceptional.api_key = TEST_API_KEY
|
117
|
+
Exceptional.authenticated?.should be_false
|
118
|
+
|
119
|
+
Exceptional.should_receive(:authenticated?).once.and_return(true)
|
120
|
+
|
121
|
+
mock_http = mock(Net::HTTP)
|
122
|
+
Net::HTTP.should_receive(:new).with("getexceptional.com", 80).once.and_return(mock_http)
|
123
|
+
|
124
|
+
mock_http_response= mock(Net::HTTPInternalServerError)
|
125
|
+
mock_http_response.should_receive(:kind_of?).with(Net::HTTPSuccess).once.and_return(false)
|
126
|
+
mock_http_response.should_receive(:code).once.and_return(501)
|
127
|
+
mock_http_response.should_receive(:message).once.and_return("Internal Server Error")
|
128
|
+
|
129
|
+
mock_http.should_receive(:start).once.and_return(mock_http_response)
|
130
|
+
|
131
|
+
#surpress the logging of the exception
|
132
|
+
Exceptional.should_receive(:log!).twice
|
133
|
+
|
134
|
+
lambda{Exceptional.post_exception("data")}.should raise_error(Exceptional::Remote::RemoteException)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|