sfalma 0.7

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.
Files changed (50) hide show
  1. data/bin/sfalma +76 -0
  2. data/init.rb +27 -0
  3. data/install.rb +19 -0
  4. data/lib/sfalma/alert_data.rb +15 -0
  5. data/lib/sfalma/application_environment.rb +79 -0
  6. data/lib/sfalma/catcher.rb +26 -0
  7. data/lib/sfalma/config.rb +93 -0
  8. data/lib/sfalma/controller_exception_data.rb +69 -0
  9. data/lib/sfalma/exception_data.rb +146 -0
  10. data/lib/sfalma/integration/alerter.rb +11 -0
  11. data/lib/sfalma/integration/dj.rb +12 -0
  12. data/lib/sfalma/integration/rack.rb +28 -0
  13. data/lib/sfalma/integration/rack_rails.rb +26 -0
  14. data/lib/sfalma/integration/rails.rb +27 -0
  15. data/lib/sfalma/integration/sinatra.rb +6 -0
  16. data/lib/sfalma/integration/tester.rb +20 -0
  17. data/lib/sfalma/log_factory.rb +39 -0
  18. data/lib/sfalma/monkeypatches.rb +10 -0
  19. data/lib/sfalma/rack_exception_data.rb +29 -0
  20. data/lib/sfalma/railtie.rb +20 -0
  21. data/lib/sfalma/remote.rb +59 -0
  22. data/lib/sfalma/startup.rb +14 -0
  23. data/lib/sfalma/vcs.rb +45 -0
  24. data/lib/sfalma/version.rb +3 -0
  25. data/lib/sfalma.rb +71 -0
  26. data/lib/tasks/sfalma_tasks.rake +11 -0
  27. data/rails/init.rb +1 -0
  28. data/sfalma.gemspec +18 -0
  29. data/spec/bin/ginger +54 -0
  30. data/spec/dj_integration_spec.rb +29 -0
  31. data/spec/fixtures/favicon.png +0 -0
  32. data/spec/fixtures/sfalma.yml +10 -0
  33. data/spec/fixtures/sfalma_disabled.yml +4 -0
  34. data/spec/ginger_scenarios.rb +33 -0
  35. data/spec/rack_integration_spec.rb +21 -0
  36. data/spec/rails_integration_spec.rb +95 -0
  37. data/spec/rails_rack_integration_spec.rb +29 -0
  38. data/spec/sfalma/alert_exception_data_spec.rb +11 -0
  39. data/spec/sfalma/catcher_spec.rb +13 -0
  40. data/spec/sfalma/config_spec.rb +64 -0
  41. data/spec/sfalma/controller_exception_data_spec.rb +26 -0
  42. data/spec/sfalma/exception_data_spec.rb +198 -0
  43. data/spec/sfalma/monkeypatches_spec.rb +11 -0
  44. data/spec/sfalma/rack_exception_data_spec.rb +87 -0
  45. data/spec/sfalma/remote_spec.rb +31 -0
  46. data/spec/sfalma/startup_spec.rb +15 -0
  47. data/spec/sfalma_rescue_spec.rb +74 -0
  48. data/spec/spec_helper.rb +23 -0
  49. data/spec/standalone_spec.rb +9 -0
  50. metadata +111 -0
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sfalma::Config, 'defaults' do
4
+ before :each do
5
+ Sfalma::Config.reset
6
+ end
7
+ it "have sensible defaults" do
8
+ Sfalma::Config.ssl?.should == false
9
+ Sfalma::Config.remote_host.should == 'api.sfalma.com'
10
+ Sfalma::Config.remote_port.should == 80
11
+ Sfalma::Config.application_root.should == Dir.pwd
12
+ Sfalma::Config.http_proxy_host.should be_nil
13
+ Sfalma::Config.http_proxy_port.should be_nil
14
+ Sfalma::Config.http_proxy_username.should be_nil
15
+ Sfalma::Config.http_proxy_password.should be_nil
16
+ Sfalma::Config.http_open_timeout.should == 2
17
+ Sfalma::Config.http_read_timeout.should == 4
18
+ end
19
+ it "have correct defaults when ssl" do
20
+ Sfalma::Config.ssl = true
21
+ Sfalma::Config.remote_host.should == 'api.sfalma.com'
22
+ Sfalma::Config.remote_port.should == 443
23
+ end
24
+ it "be disabled based on environment by default" do
25
+ %w(development test).each do |env|
26
+ Sfalma::Config.stub!(:application_environment).and_return(env)
27
+ Sfalma::Config.should_send_to_api?.should == false
28
+ end
29
+ end
30
+ it "be enabled based on environment by default" do
31
+ %w(production staging).each do |env|
32
+ Sfalma::Config.stub!(:application_environment).and_return(env)
33
+ Sfalma::Config.should_send_to_api?.should == true
34
+ end
35
+ end
36
+ context 'production environment' do
37
+ before :each do
38
+ Sfalma::Config.stub!(:application_environment).and_return('production')
39
+ end
40
+ it "allow a new simpler format for " do
41
+ Sfalma::Config.load('spec/fixtures/sfalma.yml')
42
+ Sfalma::Config.api_key.should == 'abc123'
43
+ Sfalma::Config.ssl?.should == true
44
+ Sfalma::Config.remote_host.should == 'example.com'
45
+ Sfalma::Config.remote_port.should == 123
46
+ Sfalma::Config.should_send_to_api?.should == true
47
+ Sfalma::Config.http_proxy_host.should == 'annoying-proxy.example.com'
48
+ Sfalma::Config.http_proxy_port.should == 1066
49
+ Sfalma::Config.http_proxy_username.should == 'bob'
50
+ Sfalma::Config.http_proxy_password.should == 'jack'
51
+ Sfalma::Config.http_open_timeout.should == 5
52
+ Sfalma::Config.http_read_timeout.should == 10
53
+ end
54
+ it "allow disable production environment" do
55
+ Sfalma::Config.load('spec/fixtures/sfalma_disabled.yml')
56
+ Sfalma::Config.api_key.should == 'abc123'
57
+ Sfalma::Config.should_send_to_api?.should == false
58
+ end
59
+ it "load api_key from environment variable" do
60
+ ENV.should_receive(:[]).with('SFALMA_API_KEY').any_number_of_times.and_return('98765')
61
+ Sfalma::Config.api_key.should == '98765'
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'digest/md5'
3
+
4
+
5
+ class Sfalma::FunkyError < StandardError
6
+ def backtrace
7
+ 'backtrace'
8
+ end
9
+ end
10
+
11
+ class BrokenJSON
12
+ def to_json
13
+ boom.time!
14
+ end
15
+ end
16
+
17
+ describe Sfalma::ControllerExceptionData do
18
+ it "raises useful error when to_json isn't available on to_hash" do
19
+ request = ActionController::TestRequest.new
20
+ brokenJson = BrokenJSON.new
21
+ session = {:boom => brokenJson}
22
+ request.stub!(:session).and_return(session)
23
+ data = Sfalma::ControllerExceptionData.new(Sfalma::FunkyError.new, nil, request)
24
+ JSON.parse(data.to_json)['request']['session']['data'].should == {"boom" => brokenJson.to_s}
25
+ end
26
+ end
@@ -0,0 +1,198 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'digest/md5'
3
+
4
+ class Sfalma::FunkyError < StandardError
5
+ def backtrace
6
+ 'backtrace'
7
+ end
8
+ end
9
+
10
+ describe Sfalma::ControllerExceptionData do
11
+ it "raises useful error when to_json isn't available on to_hash" do
12
+ begin
13
+ data = Sfalma::ExceptionData.new(Sfalma::FunkyError.new)
14
+ hash_without_json = {}
15
+ hash_without_json.stub!(:to_json).and_raise(NoMethodError)
16
+ data.stub!(:to_hash).and_return(hash_without_json)
17
+ data.to_json
18
+ fail 'expects to raise and error'
19
+ rescue StandardError => e
20
+ e.message.should =~ /to_json/
21
+ end
22
+ end
23
+ end
24
+
25
+ describe Sfalma::ControllerExceptionData, 'when no request/controller/params' do
26
+ before :each do
27
+ ENV['LOGNAME'] = 'bob'
28
+ ENV['SOMEVAR'] = 'something'
29
+ ENV['SOMEOTHERVAR'] = 'something else'
30
+ Sfalma::ENVIRONMENT_FILTER << 'SOMEOTHERVAR'
31
+ ENV['HTTP_SOMETHING'] = 'should be stripped'
32
+ ::RAILS_ENV = 'test' unless defined?(RAILS_ENV)
33
+ Time.stub!(:now).and_return(Time.mktime(1970, 1, 1))
34
+ error = Sfalma::FunkyError.new('some message')
35
+ @data = Sfalma::ControllerExceptionData.new(error)
36
+ @hash = @data.to_hash
37
+ end
38
+
39
+ it "capture exception details" do
40
+ error_hash = @hash['exception']
41
+ error_hash['exception_class'].should == 'Sfalma::FunkyError'
42
+ error_hash['message'].should == 'some message'
43
+ error_hash['backtrace'].should == 'backtrace'
44
+ DateTime.parse(error_hash['occurred_at']).should == DateTime.now
45
+ client_hash = @hash['client']
46
+ client_hash['name'].should == Sfalma::CLIENT_NAME
47
+ client_hash['version'].should == Sfalma::VERSION
48
+ client_hash['protocol_version'].should == Sfalma::PROTOCOL_VERSION
49
+ end
50
+
51
+ it "generates parseable json" do
52
+ require 'json'
53
+ JSON.parse(@data.to_json)['exception']['exception_class'].should == 'Sfalma::FunkyError'
54
+ end
55
+
56
+ it "capture application_environment" do
57
+ application_env_hash = @hash['application_environment']
58
+ application_env_hash['environment'].should == 'test'
59
+ application_env_hash['env'].should_not be_nil
60
+ application_env_hash['env']['SOMEVAR'].should == 'something'
61
+ application_env_hash['env']['SOMEOTHERVAR'].should == nil
62
+ application_env_hash['host'].should == `hostname`.strip
63
+ application_env_hash['run_as_user'].should == 'bob'
64
+ application_env_hash['application_root_directory'].should == Dir.pwd
65
+ application_env_hash['language'].should == 'ruby'
66
+ application_env_hash['language_version'].should == "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE} #{RUBY_PLATFORM}"
67
+ application_env_hash['framework'].should == "rails"
68
+ application_env_hash['libraries_loaded']['rails'].should =~ /\d\.\d\.\d/
69
+ end
70
+ end
71
+
72
+ describe Sfalma::ControllerExceptionData, 'with request/controller/params' do
73
+ class Sfalma::SomeController < ActionController::Base
74
+ filter_parameter_logging :filter_me
75
+ end
76
+
77
+ before :each do
78
+ @controller = Sfalma::SomeController.new
79
+ @request = ActionController::TestRequest.new({'action' => 'some_action' })
80
+ @request.request_uri = '/some_path?var1=abc'
81
+ @request.stub!(:parameters).and_return({'var1' => 'abc', 'action' => 'some_action', 'filter_me' => 'private'})
82
+ @request.stub!(:request_method).and_return(:get)
83
+ @request.stub!(:remote_ip).and_return('1.2.3.4')
84
+ @request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_CONTENT_TYPE' => 'text/html'})
85
+ @error = Sfalma::FunkyError.new('some message')
86
+ data = Sfalma::ControllerExceptionData.new(@error, @controller, @request)
87
+ @hash = data.to_hash
88
+ end
89
+
90
+ it "captures request" do
91
+ request_hash = @hash['request']
92
+ request_hash['url'].should == 'http://test.host/some_path?var1=abc'
93
+ request_hash['controller'].should == 'Sfalma::SomeController'
94
+ request_hash['action'].should == 'some_action'
95
+ request_hash['parameters'].should == {'var1' => 'abc', 'action' => 'some_action', 'filter_me' => '[FILTERED]'}
96
+ request_hash['request_method'].should == 'get'
97
+ request_hash['remote_ip'].should == '1.2.3.4'
98
+ request_hash['headers'].should == {'Content-Type' => 'text/html'}
99
+ end
100
+
101
+ it "filter out objects that aren't jsonable" do
102
+ class Crazy
103
+ def initialize
104
+ @bar = self
105
+ end
106
+ end
107
+ crazy = Crazy.new
108
+ input = {'crazy' => crazy, :simple => '123', :some_hash => {'1' => '2'}, :array => ['1', '2']}
109
+ Sfalma::ControllerExceptionData.sanitize_hash(input).should == {'crazy' => crazy.to_s, :simple => '123', :some_hash => {'1' => '2'}, :array => ['1', '2']}
110
+ end
111
+
112
+ it "allow if non jsonable objects are hidden in an array" do
113
+ class Bonkers
114
+ def to_json
115
+ no.can.do!
116
+ end
117
+ end
118
+ crazy = Bonkers.new
119
+ input = {'crazy' => [crazy]}
120
+ Sfalma::ControllerExceptionData.sanitize_hash(input).should == {'crazy' => [crazy.to_s]}
121
+ end
122
+
123
+ it "filter params specified in env['action_dispatch.parameter_filter']" do
124
+ @request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_CONTENT_TYPE' => 'text/html', 'action_dispatch.parameter_filter' => [:var1]})
125
+ @request.stub!(:parameters).and_return({'var1' => 'abc'})
126
+ data = Sfalma::ControllerExceptionData.new(@error, @controller, @request)
127
+ data.to_hash['request']['parameters'].should == {'var1' => '[FILTERED]'}
128
+ end
129
+
130
+ it "formats the occurred_at as iso8601" do
131
+ @request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_CONTENT_TYPE' => 'text/html', 'action_dispatch.parameter_filter' => [:var1]})
132
+ @request.stub!(:parameters).and_return({'var1' => 'abc'})
133
+ data = Sfalma::ControllerExceptionData.new(@error, @controller, @request)
134
+ data.to_hash['exception']['occurred_at'].should match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.{1,6}$/)
135
+ end
136
+
137
+ it "ArgumentError bug with file object" do
138
+ file = File.new(File.expand_path('../../fixtures/favicon.png',__FILE__))
139
+ @request.stub!(:parameters).and_return({'something' => file })
140
+ data = Sfalma::ControllerExceptionData.new(@error, @controller, @request)
141
+ data.to_hash['request']['parameters']['something'].should == file.to_s
142
+ end
143
+
144
+ it "to_strings regex because JSON.parse(/aa/.to_json) doesn't work" do
145
+ input = {'crazy' => /abc.*/}
146
+ Sfalma::ExceptionData.sanitize_hash(input).should == {'crazy' => /abc.*/.to_s}
147
+ end
148
+
149
+ it "handles session objects with various interfaces" do
150
+ class SessionWithInstanceVariables
151
+ def initialize
152
+ @data = {'a' => '1', 'b' => /hello there Im a regex/i}
153
+ @session_id = '123'
154
+ end
155
+ end
156
+
157
+ request = ActionController::TestRequest.new
158
+ session = SessionWithInstanceVariables.new
159
+ request.stub!(:session).and_return(session)
160
+ request.stub!(:session_options).and_return({})
161
+ Sfalma::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1', 'b' => "(?i-mx:hello there Im a regex)"}}
162
+ session = mock('session', :session_id => '123', :instance_variable_get => {'a' => '1', 'b' => /another(.+) regex/mx})
163
+ request.stub!(:session).and_return(session)
164
+ Sfalma::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1', 'b' => "(?mx-i:another(.+) regex)"}}
165
+ session = mock('session', :session_id => nil, :to_hash => {:session_id => '123', 'a' => '1'})
166
+ request.stub!(:session).and_return(session)
167
+ Sfalma::ControllerExceptionData.sanitize_session(request).should == {'session_id' => '123', 'data' => {'a' => '1'}}
168
+ request.stub!(:session_options).and_return({:id => 'xyz'})
169
+ Sfalma::ControllerExceptionData.sanitize_session(request).should == {'session_id' => 'xyz', 'data' => {'a' => '1'}}
170
+ end
171
+
172
+ it "filter session cookies from headers" do
173
+ @request.stub!(:env).and_return({'SOME_VAR' => 'abc', 'HTTP_COOKIE' => '_something_else=faafsafafasfa; _myapp-lick-nation_session=BAh7DDoMbnVtYmVyc1sJaQZpB2kIaQk6FnNvbWVfY3Jhenlfb2JqZWN0bzobU3Bpa2VDb250cm9sbGVyOjpDcmF6eQY6CUBiYXJABzoTc29tZXRoaW5nX2Vsc2UiCGNjYzoKYXBwbGUiDUJyYWVidXJuOgloYXNoewdpBmkHaQhpCToPc2Vzc2lvbl9pZCIlMmJjZTM4MjVjMThkNzYxOWEyZDA4NTJhNWY1NGQzMmU6C3RvbWF0byIJQmVlZg%3D%3D--66fb4606851f06bf409b8bc4ba7aea47a0259bf7'})
174
+ @hash = Sfalma::ControllerExceptionData.new(Sfalma::FunkyError.new('some message'), @controller, @request).to_hash
175
+ @hash['request']['headers'].should == {'Cookie' => '_something_else=faafsafafasfa; _myapp-lick-nation_session=[FILTERED]'}
176
+ end
177
+
178
+ it "creates a uniqueness_hash from backtrace" do
179
+ exception = Exception.new
180
+ exception.stub!(:backtrace).and_return(['123'])
181
+ data = Sfalma::ControllerExceptionData.new(exception)
182
+ data.uniqueness_hash.should == Digest::MD5.hexdigest('123')
183
+ end
184
+
185
+ it "creates a nil uniqueness_hash if nil backtrace" do
186
+ exception = Exception.new
187
+ exception.stub!(:backtrace).and_return(nil)
188
+ data = Sfalma::ControllerExceptionData.new(exception)
189
+ data.uniqueness_hash.should == nil
190
+ end
191
+
192
+ it "creates a uniqueness_hash from backtrace" do
193
+ exception = Exception.new
194
+ exception.stub!(:backtrace).and_return([])
195
+ data = Sfalma::ControllerExceptionData.new(exception)
196
+ data.uniqueness_hash.should == nil
197
+ end
198
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.join(File.dirname(__FILE__), '../..', 'lib', 'sfalma', 'monkeypatches')
3
+
4
+ describe Regexp do
5
+ it "should output a correctly formatted string" do
6
+ /hello/.to_json.should == "\"(?-mix:hello)\""
7
+ end
8
+ it "should output a correctly formatted string" do
9
+ 2.to_json.should == "2"
10
+ end
11
+ end
@@ -0,0 +1,87 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'digest/md5'
3
+
4
+ describe Sfalma::RackExceptionData do
5
+
6
+ class Sfalma::FunkyError < StandardError
7
+ def backtrace
8
+ 'backtrace'
9
+ end
10
+ end
11
+
12
+ before :each do
13
+ app = lambda { |env| [200, {'Content-Type'=>'text/plain'}, 'Hello World']}
14
+
15
+ @env = {
16
+ "HTTP_HOST" =>"localhost:9292",
17
+ "HTTP_ACCEPT" =>"*/*",
18
+ "SERVER_NAME" =>"localhost",
19
+ "REQUEST_PATH" =>"/",
20
+ "rack.url_scheme" =>"http",
21
+ "HTTP_USER_AGENT" =>"curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3",
22
+ "REMOTE_HOST" =>"testing.com",
23
+ "rack.errors" => StringIO.new,
24
+ "SERVER_PROTOCOL" =>"HTTP/1.1",
25
+ "rack.version" =>[1, 1],
26
+ "rack.run_once" =>false,
27
+ "SERVER_SOFTWARE" =>"WEBrick/1.3.1 (Ruby/1.8.7/2009-06-12)",
28
+ "REMOTE_ADDR" =>"127.0.0.1",
29
+ "PATH_INFO" => "/",
30
+ "SCRIPT_NAME" =>"",
31
+ "HTTP_VERSION" =>"HTTP/1.1",
32
+ "rack.multithread" =>true,
33
+ "rack.multiprocess" =>false,
34
+ "REQUEST_URI" =>"http://localhost:9292/",
35
+ "SERVER_PORT" =>"9292",
36
+ "REQUEST_METHOD" =>"GET",
37
+ "rack.input" => StringIO.new,
38
+ "QUERY_STRING" =>"cockle=shell&bay=cool",
39
+ "GATEWAY_INTERFACE" =>"CGI/1.1"
40
+ }
41
+
42
+ error = Sfalma::FunkyError.new('some message')
43
+ request = Rack::Request.new(@env)
44
+ @data = Sfalma::RackExceptionData.new(error, @env, request)
45
+ end
46
+
47
+ it "capture exception details" do
48
+ error_hash = @data.to_hash['exception']
49
+ error_hash['exception_class'].should == 'Sfalma::FunkyError'
50
+ error_hash['message'].should == 'some message'
51
+ error_hash['backtrace'].should == 'backtrace'
52
+ DateTime.parse(error_hash['occurred_at']).should == DateTime.parse(Time.now.to_json)
53
+ end
54
+
55
+ it "should capture request details" do
56
+ request_hash = @data.to_hash['request']
57
+ request_hash['url'].should == 'http://localhost:9292/?cockle=shell&bay=cool'
58
+ request_hash['parameters'].should == {"cockle"=>"shell", "bay"=>"cool"}
59
+ request_hash['request_method'].should == 'GET'
60
+ request_hash['remote_ip'].should == '127.0.0.1'
61
+ request_hash['headers'].should == {"Host"=>"localhost:9292", "Accept"=>"*/*", "User-Agent"=>"curl/7.19.6 (i386-apple-darwin9.8.0) libcurl/7.19.6 zlib/1.2.3", "Version"=>"HTTP/1.1"}
62
+ request_hash['session'].should == {'data' => {}, 'session_id' => ''}
63
+ end
64
+
65
+ it "should capture client detais" do
66
+ client_hash = @data.to_hash['client']
67
+ client_hash['name'].should == Sfalma::CLIENT_NAME
68
+ client_hash['version'].should == Sfalma::VERSION
69
+ client_hash['protocol_version'].should == Sfalma::PROTOCOL_VERSION
70
+ end
71
+
72
+ it "should captire application environment" do
73
+ env_hash = @data.to_hash['application_environment']
74
+ env_hash['env'].should_not be_empty #execution dependent
75
+ env_hash['libraries_loaded'].should_not be_empty #execution dependent
76
+ env_hash['language'].should == 'ruby' #execution dependent
77
+
78
+ env_hash['language_version'].should_not be_empty #execution dependent
79
+ env_hash['environment'].should == 'test'
80
+ env_hash['application_root_directory'].should_not be_empty
81
+ env_hash['run_as_user'].should_not be_empty
82
+ env_hash['host'].should_not be_empty
83
+
84
+ env_hash['framework'].should == 'rack'
85
+ end
86
+
87
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'zlib'
3
+ require 'digest/md5'
4
+
5
+ describe Sfalma::Remote do
6
+ before :each do
7
+ Sfalma::Config.reset
8
+ Sfalma::Config.api_key = 'abc123'
9
+ end
10
+
11
+ it "calls remote with api_key, protocol_version and json" do
12
+ expected_url = "/api/errors?api_key=abc123&protocol_version=#{Sfalma::PROTOCOL_VERSION}"
13
+ expected_data = mock('data',:uniqueness_hash => nil, :to_json => '123')
14
+ Sfalma::Remote.should_receive(:call_remote).with(expected_url, Zlib::Deflate.deflate(expected_data.to_json,Zlib::BEST_SPEED))
15
+ Sfalma::Remote.error(expected_data)
16
+ end
17
+
18
+ it "adds hash of backtrace as paramater if it is present" do
19
+ expected_url = "/api/errors?api_key=abc123&protocol_version=#{Sfalma::PROTOCOL_VERSION}&hash=blah"
20
+ expected_data = mock('data',:uniqueness_hash => 'blah', :to_json => '123')
21
+ Sfalma::Remote.should_receive(:call_remote).with(expected_url, Zlib::Deflate.deflate(expected_data.to_json,Zlib::BEST_SPEED))
22
+ Sfalma::Remote.error(expected_data)
23
+ end
24
+
25
+ it "calls remote for startup" do
26
+ expected_url = "/api/announcements?api_key=abc123&protocol_version=#{Sfalma::PROTOCOL_VERSION}"
27
+ startup_data = mock('data',:to_json => '123')
28
+ Sfalma::Remote.should_receive(:call_remote).with(expected_url, Zlib::Deflate.deflate(startup_data.to_json,Zlib::BEST_SPEED))
29
+ Sfalma::Remote.startup_announce(startup_data)
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sfalma::Startup, 'announce_and_authenticate' do
4
+ it "raise StartupException if api_key is nil" do
5
+ Sfalma::Config.api_key = ''
6
+ lambda { Sfalma::Startup.announce }.should raise_error(Sfalma::StartupException, /API Key/)
7
+ end
8
+ it "calls Remote announce" do
9
+ Sfalma::Config.api_key = '123'
10
+ Sfalma::Remote.should_receive(:startup_announce).with(hash_including({'client' => { 'name' => Sfalma::CLIENT_NAME,
11
+ 'version' => Sfalma::VERSION,
12
+ 'protocol_version' => Sfalma::PROTOCOL_VERSION}}))
13
+ Sfalma::Startup.announce
14
+ end
15
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ context 'resuce errors from within a block' do
4
+ class FunkyException < StandardError;
5
+ end
6
+ it "Sfalma.rescue should send to sfalma and swallow error " do
7
+ to_raise = FunkyException.new
8
+ Sfalma::Catcher.should_receive(:handle).with(to_raise, 'my rescue name')
9
+ Sfalma.rescue('my rescue name') do
10
+ raise to_raise
11
+ end
12
+ end
13
+
14
+ it "reraises error with rescue_and_reraise" do
15
+ to_raise = FunkyException.new
16
+ Sfalma::Catcher.should_receive(:handle).with(to_raise, 'my rescue name')
17
+ begin
18
+ Sfalma.rescue_and_reraise('my rescue name') do
19
+ raise to_raise
20
+ end
21
+ fail 'expected a reraise'
22
+ rescue FunkyException => e
23
+ end
24
+ end
25
+
26
+ it "Sfalma.handle calls Sfalma::Catcher.handle" do
27
+ to_raise = FunkyException.new
28
+ Sfalma::Catcher.should_receive(:handle).with(to_raise, 'optional name for where it has occurred')
29
+ begin
30
+ raise to_raise
31
+ rescue => e
32
+ Sfalma.handle(e, 'optional name for where it has occurred')
33
+ end
34
+ end
35
+
36
+ it "collects context information but leaves thread local empty after block" do
37
+ to_raise = FunkyException.new
38
+ Sfalma::Config.should_receive(:should_send_to_api?).and_return(true)
39
+ Sfalma::Remote.should_receive(:error) {|exception_data|
40
+ exception_data.to_hash['context']['foo'] == 'bar'
41
+ exception_data.to_hash['context']['baz'] == 42
42
+ exception_data.to_hash['context']['cats'] == {'lol' => 'bot'}
43
+ }
44
+ Sfalma.rescue('my rescue name') do
45
+ Sfalma.context('foo' => 'bar')
46
+ Sfalma.context('baz' => 42)
47
+ Sfalma.context('cats' => {'lol' => 'bot'})
48
+ raise to_raise
49
+ end
50
+ Thread.current[:exceptional_context].should == nil
51
+ end
52
+
53
+ it "clearr context with Sfalma.context.clear!" do
54
+ Sfalma.context('foo' => 'bar')
55
+ Thread.current[:exceptional_context].should_not == nil
56
+ Sfalma.context.clear!
57
+ Thread.current[:exceptional_context].should == nil
58
+ end
59
+
60
+ it "allows optional second paramater hash to get added to context" do
61
+ Sfalma.should_receive(:context).with(context_hash = {'foo' => 'bar', 'baz' => 42})
62
+ Sfalma.rescue('my rescue', context_hash) {}
63
+ end
64
+
65
+ it "should clear context after every invocation" do
66
+ Thread.current[:exceptional_context].should == nil
67
+
68
+ Sfalma.rescue('my rescue', context_hash = {'foo' => 'bar', 'baz' => 42}) {
69
+ Thread.current[:exceptional_context].should_not == nil
70
+ }
71
+
72
+ Thread.current[:exceptional_context].should == nil
73
+ end
74
+ end
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ begin
3
+ require 'ginger'
4
+ rescue LoadError
5
+ raise "cant load ginger"
6
+ end
7
+
8
+ gem 'rails'
9
+ require File.dirname(__FILE__) + '/../lib/sfalma' unless defined?(Sfalma)
10
+
11
+ ENV['RAILS_ENV'] = 'test'
12
+
13
+ require 'action_controller'
14
+ require 'action_controller/test_process'
15
+
16
+ def send_request(action = nil,params={})
17
+ @request = ActionController::TestRequest.new
18
+ @request.query_parameters = @request.query_parameters.merge(params)
19
+ @request.stub!(:request_method).and_return('GET')
20
+ @request.action = action ? action.to_s : ""
21
+ @response = ActionController::TestResponse.new
22
+ @controller.process(@request, @response)
23
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sfalma', 'integration', 'rails')
3
+
4
+ describe Sfalma do
5
+ it "set the api key" do
6
+ Sfalma.configure('api-key')
7
+ Sfalma::Config.api_key.should == 'api-key'
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sfalma
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.7'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sfalma
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-05-05 00:00:00.000000000 +03:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ requirement: &15079640 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *15079640
26
+ description: ! 'Sfalma is the Ruby gem for communicating with http://sfalma.com (hosted
27
+ error tracking service). Use it to find out about errors that happen in your web
28
+ or mobile app. '
29
+ email: info@sfalma.com
30
+ executables:
31
+ - sfalma
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - lib/tasks/sfalma_tasks.rake
36
+ - lib/sfalma/vcs.rb
37
+ - lib/sfalma/config.rb
38
+ - lib/sfalma/log_factory.rb
39
+ - lib/sfalma/rack_exception_data.rb
40
+ - lib/sfalma/railtie.rb
41
+ - lib/sfalma/application_environment.rb
42
+ - lib/sfalma/version.rb
43
+ - lib/sfalma/integration/dj.rb
44
+ - lib/sfalma/integration/rack_rails.rb
45
+ - lib/sfalma/integration/rack.rb
46
+ - lib/sfalma/integration/rails.rb
47
+ - lib/sfalma/integration/alerter.rb
48
+ - lib/sfalma/integration/tester.rb
49
+ - lib/sfalma/integration/sinatra.rb
50
+ - lib/sfalma/remote.rb
51
+ - lib/sfalma/monkeypatches.rb
52
+ - lib/sfalma/alert_data.rb
53
+ - lib/sfalma/startup.rb
54
+ - lib/sfalma/controller_exception_data.rb
55
+ - lib/sfalma/catcher.rb
56
+ - lib/sfalma/exception_data.rb
57
+ - lib/sfalma.rb
58
+ - spec/rails_integration_spec.rb
59
+ - spec/sfalma_rescue_spec.rb
60
+ - spec/ginger_scenarios.rb
61
+ - spec/fixtures/favicon.png
62
+ - spec/fixtures/sfalma.yml
63
+ - spec/fixtures/sfalma_disabled.yml
64
+ - spec/bin/ginger
65
+ - spec/rails_rack_integration_spec.rb
66
+ - spec/rack_integration_spec.rb
67
+ - spec/sfalma/alert_exception_data_spec.rb
68
+ - spec/sfalma/rack_exception_data_spec.rb
69
+ - spec/sfalma/startup_spec.rb
70
+ - spec/sfalma/config_spec.rb
71
+ - spec/sfalma/catcher_spec.rb
72
+ - spec/sfalma/remote_spec.rb
73
+ - spec/sfalma/exception_data_spec.rb
74
+ - spec/sfalma/monkeypatches_spec.rb
75
+ - spec/sfalma/controller_exception_data_spec.rb
76
+ - spec/spec_helper.rb
77
+ - spec/dj_integration_spec.rb
78
+ - spec/standalone_spec.rb
79
+ - rails/init.rb
80
+ - init.rb
81
+ - install.rb
82
+ - sfalma.gemspec
83
+ - bin/sfalma
84
+ has_rdoc: true
85
+ homepage: http://sfalma.com/
86
+ licenses: []
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements:
104
+ - json_pure, json-jruby or json gem required
105
+ rubyforge_project: sfalma
106
+ rubygems_version: 1.5.3
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: sfalma.com is a cloud-based error tracker with a social twist with a focus
110
+ on mobile apps
111
+ test_files: []