captivus 0.0.2

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in captivus.gemspec
4
+ gemspec
5
+
6
+ gem "rspec", "~> 2.11"
7
+ gem "sham_rack", "~> 1.3"
8
+ gem "rack-test", "~> 0.6"
9
+ gem "timecop", '~> 0.5'
10
+ gem "delorean", "~> 2.0.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Austin Schneider
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Captivus
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'captivus'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install captivus
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/captivus.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'captivus/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "captivus"
8
+ gem.version = Captivus::VERSION
9
+ gem.authors = ["Austin Schneider"]
10
+ gem.email = ["austinthecoder@gmail.com"]
11
+ gem.description = "Captivus client gem"
12
+ gem.summary = "Captivus client gem"
13
+ gem.homepage = "http://captiv.us"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "faraday", '~> 0.8.4'
21
+ gem.add_dependency "multi_json", "~> 1.3.6"
22
+ gem.add_dependency "captivus-auth_hmac", "0.0.1"
23
+ end
@@ -0,0 +1,21 @@
1
+ module Captivus
2
+ class Backtrace
3
+ class Line
4
+ PATTERN = /^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/
5
+
6
+ def initialize(raw_line)
7
+ if match_data = PATTERN.match(raw_line)
8
+ @as_json = {
9
+ :file => match_data[1],
10
+ :number => match_data[2].to_i,
11
+ :method => match_data[3]
12
+ }
13
+ else
14
+ raise ArgumentError, "Unrecognized format"
15
+ end
16
+ end
17
+
18
+ attr_reader :as_json
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ require 'captivus/backtrace/line'
2
+
3
+ module Captivus
4
+ class Backtrace
5
+ def initialize(exception)
6
+ unless exception.respond_to?(:backtrace)
7
+ raise ArgumentError, "#{exception} must respond to `backtrace`"
8
+ end
9
+ @as_json = Array(exception.backtrace).map { |line| Line.new(line).as_json }
10
+ end
11
+
12
+ attr_reader :as_json
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module Captivus
2
+ class Configuration
3
+ def initialize(attrs = {}, &block)
4
+ defaults = {
5
+ :scheme => 'http',
6
+ :host => 'api.captiv.us'
7
+ }
8
+ configure defaults.merge(attrs), &block
9
+ end
10
+
11
+ attr_accessor :host, :scheme, :api_key, :api_secret_key
12
+
13
+ def configure(attrs = {})
14
+ attrs.each { |attr, value| send "#{attr}=", value }
15
+ yield self if block_given?
16
+ self
17
+ end
18
+
19
+ def ==(other)
20
+ other.is_a?(Captivus::Configuration) && host == other.host
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ module Captivus
2
+ class Payload
3
+ def initialize(exception)
4
+ if exception.respond_to?(:class) && exception.class.respond_to?(:name) && exception.respond_to?(:message)
5
+ @as_json = {
6
+ 'event' => {
7
+ 'type' => exception.class.name,
8
+ 'message' => exception.message,
9
+ 'timestamp' => Time.now.utc.to_s
10
+ },
11
+ 'backtrace' => Backtrace.new(exception).as_json
12
+ }
13
+ else
14
+ raise ArgumentError, "Unexpected exception: #{exception.inspect}"
15
+ end
16
+ end
17
+
18
+ attr_reader :as_json
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'faraday'
2
+ require 'multi_json'
3
+
4
+ module Captivus
5
+ class RackCapturer
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ begin
12
+ @app.call env
13
+ rescue => exception
14
+ Captivus.notify exception
15
+ raise
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :app
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Captivus
2
+ VERSION = "0.0.2"
3
+ end
data/lib/captivus.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "captivus/version"
2
+ require 'captivus/configuration'
3
+ require 'faraday/request/hmac_authentication'
4
+
5
+ module Captivus
6
+ class << self
7
+ def config
8
+ @config ||= Configuration.new
9
+ end
10
+
11
+ def configure(*args, &block)
12
+ config.configure *args, &block
13
+ end
14
+
15
+ def notify(exception)
16
+ connection = Faraday.new(:url => "#{config.scheme}://#{config.host}") do |faraday|
17
+ faraday.request :hmac_authentication, config.api_key, config.api_secret_key, {:service_id => 'Captivus'}
18
+ faraday.adapter :net_http
19
+ end
20
+
21
+ connection.post do |request|
22
+ request.headers['Content-Type'] = 'application/json; charset=UTF-8'
23
+ request.url '/events'
24
+ request.body = MultiJson.dump(Payload.new(exception).as_json)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ require 'captivus/auth_hmac'
31
+ require 'captivus/backtrace'
32
+ require 'captivus/payload'
33
+ require 'captivus/rack_capturer'
@@ -0,0 +1,69 @@
1
+ require 'captivus/auth_hmac'
2
+ require 'uri'
3
+ require 'faraday'
4
+
5
+ module Faraday
6
+ class Request
7
+
8
+ attr_reader :access_id, :secret
9
+
10
+ # # Sign the request with the specified `access_id` and `secret`.
11
+ # def sign!(access_id, secret)
12
+ # @access_id, @secret = access_id, secret
13
+
14
+ # #self.sign_with = access_id
15
+ # #Captivus::AuthHMAC.keys[access_id] = secret
16
+ # end
17
+
18
+ class HMACAuthentication < Faraday::Middleware
19
+ # Modified CanonicalString to know how to pull from the Faraday-specific
20
+ # env hash.
21
+ class CanonicalString < Captivus::AuthHMAC::CanonicalString
22
+ def request_method(request)
23
+ request[:method].to_s.upcase
24
+ end
25
+
26
+ def request_body(request)
27
+ request[:body]
28
+ end
29
+
30
+ def request_path(request)
31
+ URI.parse(request[:url].to_s).path
32
+ end
33
+
34
+ def headers(request)
35
+ request[:request_headers]
36
+ end
37
+ end
38
+
39
+ KEY = "Authorization".freeze
40
+
41
+ attr_reader :auth, :token, :secret
42
+
43
+ def initialize(app, token, secret, options = {})
44
+ options.merge!(:signature => HMACAuthentication::CanonicalString)
45
+ keys = {token => secret}
46
+ @token, @secret = token, secret
47
+ @auth = Captivus::AuthHMAC.new(keys, options)
48
+ super(app)
49
+ end
50
+
51
+ # Public
52
+ def call(env)
53
+ env[:request_headers][KEY] ||= hmac_auth_header(env).to_s if sign_request?
54
+ @app.call(env)
55
+ end
56
+
57
+ def hmac_auth_header(env)
58
+ auth.authorization(env, token, secret)
59
+ end
60
+
61
+ def sign_request?
62
+ !!@token && !!@secret
63
+ end
64
+ end
65
+ end
66
+
67
+ Faraday.register_middleware :request, :hmac_authentication => Faraday::Request::HMACAuthentication
68
+ end
69
+
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus::Backtrace::Line do
4
+ def new_line(*args)
5
+ Captivus::Backtrace::Line.new *args
6
+ end
7
+
8
+ describe ".new" do
9
+ it "raises an argument error when the line is not a correctly formatted backtrace line" do
10
+ [
11
+ nil,
12
+ ' ',
13
+ 'foo',
14
+ '/Users/austin/something.rb:10:',
15
+ "/Users/austin/something.rb:10:in 'something'",
16
+ ].each do |line|
17
+ expect { new_line line }.to raise_error(ArgumentError, "Unrecognized format")
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "as_json" do
23
+ context "when the line has the format <file>:<number>" do
24
+ it "returns the parts, minus the method, in a hash" do
25
+ new_line("/Users/austin/dir/run-file.rb:1").as_json.should == {
26
+ :file => '/Users/austin/dir/run-file.rb',
27
+ :number => 1,
28
+ :method => nil
29
+ }
30
+ end
31
+ end
32
+
33
+ context "when the line has the format <file>:<number>:in `<method>'" do
34
+ it "returns the parts in a hash" do
35
+ new_line("/Users/austin/go.rb:10:in `perform'").as_json.should == {
36
+ :file => '/Users/austin/go.rb',
37
+ :number => 10,
38
+ :method => 'perform'
39
+ }
40
+ end
41
+ end
42
+
43
+ context "when the line has the format <drive>:<file>:<number>:in `<method>'" do
44
+ it "returns the parts in a hash" do
45
+ new_line("C:/Users/austin/go.rb:10:in `perform'").as_json.should == {
46
+ :file => 'C:/Users/austin/go.rb',
47
+ :number => 10,
48
+ :method => 'perform'
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus::Backtrace do
4
+ def new_backtrace(*args)
5
+ Captivus::Backtrace.new *args
6
+ end
7
+
8
+ describe ".new" do
9
+ context "when the given object doesn't respond to `backtrace`" do
10
+ it "raises an argument error" do
11
+ object = double 'object'
12
+ expect {
13
+ new_backtrace object
14
+ }.to raise_error(ArgumentError, "#{object} must respond to `backtrace`")
15
+ end
16
+ end
17
+ end
18
+
19
+ describe 'as_json' do
20
+ before do
21
+ @object = double 'object', :backtrace => ['/Users/x.rb:1', '/Users/x.rb:2', '/Users/x.rb:3']
22
+ end
23
+
24
+ context "when the object has a backtrace" do
25
+ it 'is an array of the backtrace lines as json' do
26
+ new_backtrace(@object).as_json.should == [
27
+ Captivus::Backtrace::Line.new('/Users/x.rb:1').as_json,
28
+ Captivus::Backtrace::Line.new('/Users/x.rb:2').as_json,
29
+ Captivus::Backtrace::Line.new('/Users/x.rb:3').as_json
30
+ ]
31
+ end
32
+ end
33
+
34
+ context "when the object doesn't have a backtrace" do
35
+ it "is an empty array" do
36
+ @object.stub :backtrace
37
+ new_backtrace(@object).as_json.should == []
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus::Configuration do
4
+ [
5
+ ['scheme', 'http'],
6
+ ['host', 'api.captiv.us'],
7
+ ['api_key', nil],
8
+ ['api_secret_key', nil]
9
+ ].each do |attribute, default_value|
10
+ describe attribute do
11
+ it "defaults to #{default_value.inspect}" do
12
+ expect(eval("Captivus::Configuration.new.#{attribute}")).to eq default_value
13
+ end
14
+
15
+ it "is the given #{attribute.to_sym} option" do
16
+ expect(eval("Captivus::Configuration.new(:#{attribute} => 'x').#{attribute}")).to eq 'x'
17
+ expect(eval("Captivus::Configuration.new(:#{attribute} => ' ').#{attribute}")).to eq ' '
18
+ expect(eval("Captivus::Configuration.new(:#{attribute} => nil).#{attribute}")).to be_nil
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "host" do
24
+ it "defaults to api.captiv.us" do
25
+ expect(Captivus::Configuration.new.host).to eq 'api.captiv.us'
26
+ end
27
+
28
+ it "is the given host option" do
29
+ expect(Captivus::Configuration.new(:host => 'x').host).to eq 'x'
30
+ expect(Captivus::Configuration.new(:host => ' ').host).to eq ' '
31
+ expect(Captivus::Configuration.new(:host => nil).host).to be_nil
32
+ end
33
+ end
34
+
35
+ describe "configure" do
36
+ before { @config = Captivus::Configuration.new }
37
+
38
+ it "sets its attributes from the given hash" do
39
+ @config.configure :host => 'newho.st'
40
+ expect(@config.host).to eq 'newho.st'
41
+ end
42
+
43
+ it "yields itself if given a block" do
44
+ @config.configure do |config|
45
+ expect(config).to eq @config
46
+ end
47
+ end
48
+
49
+ it "returns itself" do
50
+ expect(@config.configure).to equal @config
51
+ end
52
+ end
53
+
54
+ describe "==" do
55
+ it "is true given another configuration with the same attributes" do
56
+ expect(Captivus::Configuration.new(:host => 'a')).to eq Captivus::Configuration.new(:host => 'a')
57
+ end
58
+
59
+ it "is false given another configuration with different attributes" do
60
+ expect(Captivus::Configuration.new).to_not eq Captivus::Configuration.new(:host => 'a')
61
+ end
62
+
63
+ it "is false given a non configuration" do
64
+ expect(Captivus::Configuration.new).to_not eq Object.new
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus::Payload do
4
+ describe ".new" do
5
+ context "when argument doesn't behave like an exception" do
6
+ it "raises an argument error" do
7
+ [
8
+ double('exception'),
9
+ double('exception', :class => double('class')),
10
+ double('exception', :class => double('class', :name => 'X')),
11
+ double('exception', :class => double('class'), :message => 'x')
12
+ ].each do |exception|
13
+ expect {
14
+ Captivus::Payload.new exception
15
+ }.to raise_error(ArgumentError, "Unexpected exception: #{exception.inspect}")
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "as_json" do
22
+ it "returns a hash of event and backtrace info" do
23
+ Timecop.freeze Time.utc(2012, 8, 23, 16, 34, 19)
24
+
25
+ exception = double 'exception',
26
+ :class => double('class', :name => 'ExceptionType'),
27
+ :message => 'The exception message.',
28
+ :backtrace => ['/Users/x.rb:1', '/Users/x.rb:2', '/Users/x.rb:3']
29
+
30
+ Captivus::Payload.new(exception).as_json.tap do |hash|
31
+ expect(hash.keys).to match_array ['event', 'backtrace']
32
+
33
+ hash['event'].tap do |event|
34
+ expect(event.keys).to match_array ['type', 'message', 'timestamp']
35
+
36
+ expect(event['type']).to eq 'ExceptionType'
37
+ expect(event['message']).to eq 'The exception message.'
38
+ expect(event['timestamp']).to eq '2012-08-23 16:34:19 UTC'
39
+ end
40
+
41
+ hash['backtrace'].should == Captivus::Backtrace.new(exception).as_json
42
+ end
43
+
44
+ Timecop.return
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus::RackCapturer do
4
+ describe "call" do
5
+ before do
6
+ @app = double 'app'
7
+ @rack_capturer = Captivus::RackCapturer.new @app
8
+ end
9
+
10
+ it "is delegated to the given app, passing the env along" do
11
+ env = double 'env'
12
+ result = double 'result'
13
+ @app.stub(:call).with(env) { result }
14
+ expect(@rack_capturer.call(env)).to eq result
15
+ end
16
+
17
+ context "when calling the app raises an error" do
18
+ before { @app.stub(:call) { raise StandardError, 'Error raised' } }
19
+
20
+ it "raises the error" do
21
+ expect { @rack_capturer.call double('env') }.to raise_error StandardError, "Error raised"
22
+ end
23
+
24
+ it "notifies the Captivus API" do
25
+ Captivus.should_receive(:notify).with kind_of(StandardError)
26
+ @rack_capturer.call double('env') rescue nil
27
+ end
28
+ end
29
+
30
+ context "when calling the app does not raise an error" do
31
+ before { @app.stub :call }
32
+
33
+ it "does not notify the Captivus API" do
34
+ @rack_capturer.call double('env')
35
+ expect(captivus_api.requests.size).to eq 0
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Captivus do
4
+ describe ".configuration" do
5
+ it "is a configuration" do
6
+ expect(Captivus.config).to eq Captivus::Configuration.new
7
+ end
8
+
9
+ it "always returns the same configuration" do
10
+ expect(Captivus.config).to equal Captivus.config
11
+ end
12
+ end
13
+
14
+ describe ".configure" do
15
+ it "is delegated to the config" do
16
+ attrs = {:a => 1, :b => 2}
17
+ block = Proc.new {}
18
+ Captivus.config.should_receive(:configure).with(attrs, &block)
19
+ Captivus.configure attrs, &block
20
+ end
21
+ end
22
+
23
+ describe ".notify" do
24
+ it "sends a notice to the Captivus API" do
25
+ Timecop.freeze Time.utc(2012, 11, 28, 2, 46, 4)
26
+
27
+ exception = StandardError.new('Error raised')
28
+
29
+ Captivus.configure do |config|
30
+ config.api_key = 'api-key'
31
+ config.api_secret_key = 'secret'
32
+ end
33
+
34
+ Captivus.notify exception
35
+
36
+ expect(captivus_api.requests.size).to eq 1
37
+
38
+ headers = {
39
+ "CONTENT_TYPE"=>"application/json; charset=UTF-8",
40
+ "HTTP_ACCEPT" => "*/*",
41
+ "HTTP_USER_AGENT" => "Ruby",
42
+ "HTTP_DATE" => "Wed, 28 Nov 2012 02:46:04 GMT",
43
+ "HTTP_AUTHORIZATION" => "Captivus api-key:IgBW675pSKkCuD4McYnX9QQMI5g=",
44
+ "PATH_INFO" => "/events",
45
+ "QUERY_STRING" => "",
46
+ "REQUEST_METHOD"=>"POST",
47
+ "SCRIPT_NAME" => "",
48
+ "SERVER_NAME" => "api.captiv.us",
49
+ "SERVER_PORT" => "80",
50
+ "rack.url_scheme" => "http"
51
+ }
52
+
53
+ last_request = captivus_api.requests[0]
54
+
55
+ expect(last_request.values_at(*headers.keys)).to eq headers.values
56
+
57
+ expect(last_request['rack.input'].read).to eq MultiJson.dump(Captivus::Payload.new(exception).as_json)
58
+
59
+ Timecop.return
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Reporting from a rack app' do
4
+ include Rack::Test::Methods
5
+
6
+ before do
7
+ Captivus.configure do |config|
8
+ config.api_key = 'api-key'
9
+ config.api_secret_key = 'secret'
10
+ end
11
+ end
12
+
13
+ context "when installed as middleware in a Rack app" do
14
+ def app
15
+ Rack::Builder.app do
16
+ use Captivus::RackCapturer
17
+ run lambda { |env| raise StandardError, "Error from Rack app" }
18
+ end
19
+ end
20
+
21
+ it "errors are raised as expected" do
22
+ expect { get '/' }.to raise_error StandardError, "Error from Rack app"
23
+ end
24
+
25
+ it "reports errors to the Captivus API" do
26
+ Timecop.freeze Time.utc(2012, 8, 23, 16, 34, 19)
27
+
28
+ get '/' rescue nil
29
+
30
+ expect(captivus_api.requests.size).to eq 1
31
+
32
+ last_request = captivus_api.requests[0]
33
+
34
+ headers = {
35
+ "CONTENT_TYPE"=>"application/json; charset=UTF-8",
36
+ "HTTP_ACCEPT" => "*/*",
37
+ "HTTP_USER_AGENT" => "Ruby",
38
+ "HTTP_DATE" => "Thu, 23 Aug 2012 16:34:19 GMT",
39
+ "HTTP_AUTHORIZATION" => "Captivus api-key:syLWMLH8mJ4jTFGO2lVe+9PfgVo=",
40
+ "PATH_INFO" => "/events",
41
+ "QUERY_STRING" => "",
42
+ "REQUEST_METHOD"=>"POST",
43
+ "SCRIPT_NAME" => "",
44
+ "SERVER_NAME" => "api.captiv.us",
45
+ "SERVER_PORT" => "80",
46
+ "rack.url_scheme" => "http"
47
+ }
48
+
49
+ expect(last_request.values_at(*headers.keys)).to eq headers.values
50
+
51
+ MultiJson.load(last_request['rack.input'].read).tap do |payload|
52
+ expect(payload.keys).to match_array ['event', 'backtrace']
53
+
54
+ payload['event'].tap do |event|
55
+ expect(event.keys).to match_array ['type', 'message', 'timestamp']
56
+
57
+ expect(event['type']).to eq "StandardError"
58
+ expect(event['message']).to eq "Error from Rack app"
59
+ expect(event['timestamp']).to eq "2012-08-23 16:34:19 UTC"
60
+ end
61
+
62
+ expect(payload['backtrace'].size > 10).to be_true
63
+ expect(payload['backtrace'][0..2]).to eq [{
64
+ "file" => "/Users/austin/projects/captivus/gem/spec/integration/events_from_rack_spec.rb",
65
+ "number"=> 17,
66
+ "method" => "block (2 levels) in app"
67
+ }, {
68
+ "file" => "/Users/austin/projects/captivus/gem/lib/captivus/rack_capturer.rb",
69
+ "number"=> 12,
70
+ "method" => "call"
71
+ }, {
72
+ "file" => "/Users/austin/projects/captivus/gem/lib/captivus/rack_capturer.rb",
73
+ "number"=> 12,
74
+ "method" => "call"
75
+ }]
76
+ end
77
+
78
+ Timecop.return
79
+
80
+ # possible things to care about
81
+ # "GATEWAY_INTERFACE"=>"CGI/1.1",
82
+ # "REMOTE_ADDR"=>"127.0.0.1",
83
+ # "REMOTE_HOST"=>"localhost",
84
+ # "REQUEST_URI"=>"http://localhost:9293/events",
85
+ # "SERVER_PROTOCOL"=>"HTTP/1.1",
86
+ # "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)",
87
+ # "HTTP_CONNECTION"=>"close",
88
+ # "HTTP_HOST"=>"localhost:9293",
89
+ # "HTTP_VERSION"=>"HTTP/1.1",
90
+ # "REQUEST_PATH"=>"/events"
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,37 @@
1
+ require 'bundler/setup'
2
+ require 'sham_rack'
3
+ require 'rack/test'
4
+ require 'timecop'
5
+ require "delorean"
6
+ require_relative '../lib/captivus'
7
+
8
+ class CaptivusAPI
9
+ def call(env)
10
+ requests << env
11
+ [200, {}, ['']]
12
+ end
13
+
14
+ def requests
15
+ @requests ||= []
16
+ end
17
+
18
+ def clear_requests!
19
+ @requests = []
20
+ end
21
+ end
22
+
23
+ module Helpers
24
+ def captivus_api
25
+ @captivus_api ||= CaptivusAPI.new
26
+ end
27
+ end
28
+
29
+ RSpec.configure do |config|
30
+ config.include Helpers
31
+ config.include Delorean
32
+
33
+ config.before do
34
+ ShamRack.mount captivus_api, "api.captiv.us"
35
+ captivus_api.clear_requests!
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: captivus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Austin Schneider
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.3.6
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.3.6
46
+ - !ruby/object:Gem::Dependency
47
+ name: captivus-auth_hmac
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.1
62
+ description: Captivus client gem
63
+ email:
64
+ - austinthecoder@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - captivus.gemspec
75
+ - lib/captivus.rb
76
+ - lib/captivus/backtrace.rb
77
+ - lib/captivus/backtrace/line.rb
78
+ - lib/captivus/configuration.rb
79
+ - lib/captivus/payload.rb
80
+ - lib/captivus/rack_capturer.rb
81
+ - lib/captivus/version.rb
82
+ - lib/faraday/request/hmac_authentication.rb
83
+ - spec/captivus/backtrace/line_spec.rb
84
+ - spec/captivus/backtrace_spec.rb
85
+ - spec/captivus/configuration_spec.rb
86
+ - spec/captivus/payload_spec.rb
87
+ - spec/captivus/rack_capturer_spec.rb
88
+ - spec/captivus_spec.rb
89
+ - spec/integration/events_from_rack_spec.rb
90
+ - spec/spec_helper.rb
91
+ homepage: http://captiv.us
92
+ licenses: []
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.24
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Captivus client gem
115
+ test_files:
116
+ - spec/captivus/backtrace/line_spec.rb
117
+ - spec/captivus/backtrace_spec.rb
118
+ - spec/captivus/configuration_spec.rb
119
+ - spec/captivus/payload_spec.rb
120
+ - spec/captivus/rack_capturer_spec.rb
121
+ - spec/captivus_spec.rb
122
+ - spec/integration/events_from_rack_spec.rb
123
+ - spec/spec_helper.rb