bullion_vault 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module BullionVault
2
+ VERSION = '0.1.0'.freeze if ! defined?(::BullionVault::VERSION)
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Request::CookieAuth < Faraday::Middleware
5
+ def call(env)
6
+ env[:request_headers]['Cookie'] = @cookie
7
+ @app.call(env)
8
+ end
9
+
10
+ def initialize(app, cookie)
11
+ @app, @cookie = app, cookie
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Response::RaiseHttp4xx < Response::Middleware
5
+ def self.register_on_complete(env)
6
+ env[:response].on_complete do |response|
7
+ case response[:status].to_i
8
+ when 400
9
+ raise BullionVault::BadRequest, error_message(response)
10
+ when 401
11
+ raise BullionVault::Unauthorized, error_message(response)
12
+ when 403
13
+ raise BullionVault::Forbidden, error_message(response)
14
+ when 404
15
+ raise BullionVault::NotFound, error_message(response)
16
+ when 406
17
+ raise BullionVault::NotAcceptable, error_message(response)
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize(app)
23
+ super
24
+ @parser = nil
25
+ end
26
+
27
+ private
28
+
29
+ def self.error_message(response)
30
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{response[:status]}#{error_body(response[:body])}"
31
+ end
32
+
33
+ def self.error_body(body)
34
+ if body.nil?
35
+ nil
36
+ elsif body['error']
37
+ ": #{body['error']}"
38
+ elsif body['errors']
39
+ first = body['errors'].to_a.first
40
+ if first.kind_of? Hash
41
+ ": #{first['message'].chomp}"
42
+ else
43
+ ": #{first.chomp}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Response::RaiseHttp5xx < Response::Middleware
5
+ def self.register_on_complete(env)
6
+ env[:response].on_complete do |response|
7
+ case response[:status].to_i
8
+ when 500
9
+ raise BullionVault::InternalServerError, error_message(response, 'Something is technically wrong.')
10
+ when 502
11
+ raise BullionVault::BadGateway, error_message(response, 'BullionVault is down or being upgraded.')
12
+ when 503
13
+ raise BullionVault::ServiceUnavailable, error_message(response, '(__-){ BullionVault is over capacity.')
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize(app)
19
+ super
20
+ @parser = nil
21
+ end
22
+
23
+ private
24
+
25
+ def self.error_message(response, body=nil)
26
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{[response[:status].to_s + ':', body].compact.join(' ')} Check http://goldnews.bullionvault.com/ for updates on the status of the BullionVault service."
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ require 'faraday'
2
+
3
+ module Faraday
4
+ class Response::RaiseInvalidCookie < Response::Middleware
5
+ def self.register_on_complete(env)
6
+ env[:response].on_complete do |response|
7
+ if response[:response_headers]['set-cookie']
8
+ raise BullionVault::InvalidCookie, error_message(response)
9
+ end
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def self.error_message(response)
16
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{response[:status]}#{error_body(response[:body])}"
17
+ end
18
+
19
+ def self.error_body(body)
20
+ if body.nil?
21
+ nil
22
+ elsif body['error']
23
+ ": #{body['error']}"
24
+ elsif body['errors']
25
+ first = body['errors'].to_a.first
26
+ if first.kind_of? Hash
27
+ ": #{first['message'].chomp}"
28
+ else
29
+ ": #{first.chomp}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,67 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe BullionVault::API do
4
+ before(:each) do
5
+ @keys = BullionVault::Configuration::VALID_OPTIONS_KEYS
6
+ end
7
+
8
+ context 'with module configuration' do
9
+
10
+ before do
11
+ BullionVault.configure do |config|
12
+ @keys.each do |key|
13
+ config.public_send("#{key}=", key)
14
+ end
15
+ end
16
+ end
17
+
18
+ after do
19
+ BullionVault.reset
20
+ end
21
+
22
+ it 'inherits module configuration' do
23
+ api = BullionVault::API.new
24
+ @keys.each do |key|
25
+ api.public_send(key).should == key
26
+ end
27
+ end
28
+
29
+ context 'with class configuration' do
30
+
31
+ before do
32
+ @configuration = {
33
+ :user_login => 'login',
34
+ :user_password => 'secret',
35
+ :adapter => :typhoeus,
36
+ :endpoint => 'http://example.com/',
37
+ :format => :xml,
38
+ :proxy => 'http://user:passwd@proxy.example.com:8080',
39
+ :cookie => 'COOKIE_DATA',
40
+ :user_agent => 'Custom User Agent',
41
+ }
42
+ end
43
+
44
+ context 'during initialization'
45
+
46
+ it 'overrides module configuration' do
47
+ api = BullionVault::API.new(@configuration)
48
+ @keys.each do |key|
49
+ api.public_send(key).should == @configuration[key]
50
+ end
51
+ end
52
+
53
+ context 'after initilization' do
54
+
55
+ it 'overrides module configuration after initialization' do
56
+ api = BullionVault::API.new
57
+ @configuration.each do |key, value|
58
+ api.public_send("#{key}=", value)
59
+ end
60
+ @keys.each do |key|
61
+ api.public_send(key).should == @configuration[key]
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe BullionVault::Client::Login do
4
+ describe '#reset_cookie' do
5
+ before(:each) do
6
+ @client = BullionVault::Client.new(:user_login => 'user', :user_password => 'pass')
7
+ end
8
+
9
+ it 'resets the cookie with a new value from the server' do
10
+ stub_request(:get, 'https://live.bullionvault.com/secure/login.do')
11
+ .to_return(:status => 200, :headers => {'set-cookie' => 'monster'})
12
+
13
+ @client.send(:reset_cookie).should eq 'monster'
14
+ @client.cookie.should eq 'monster'
15
+ end
16
+ end
17
+
18
+ describe '#login' do
19
+ before(:each) do
20
+ @client = BullionVault::Client.new(
21
+ :user_login => 'user',
22
+ :user_password => 'pass',
23
+ :cookie => 'monster',
24
+ )
25
+ end
26
+
27
+ it 'posts the login credentials' do
28
+ stub_request(:post, 'https://live.bullionvault.com/secure/j_security_check')
29
+ .with(:body => 'j_username=user&j_password=pass', :headers => {'Cookie' => 'monster'})
30
+ .to_return(:status => 302, :headers => {'location' => 'https://live.bullionvault.com/secure/main_frame.do'})
31
+
32
+ @client.send(:login).should be_true
33
+ end
34
+
35
+ it 'fails when the server redirects to an unexpected URL' do
36
+ stub_request(:post, 'https://live.bullionvault.com/secure/j_security_check')
37
+ .with(:body => 'j_username=user&j_password=pass', :headers => {'Cookie' => 'monster'})
38
+ .to_return(:status => 302, :headers => {'location' => 'https://live.bullionvault.com/secure/surprise.do'})
39
+
40
+ @client.send(:login).should be_false
41
+ end
42
+
43
+ it 'fails when the server returns a response other than 302' do
44
+ stub_request(:post, 'https://live.bullionvault.com/secure/j_security_check')
45
+ .with(:body => 'j_username=user&j_password=pass', :headers => {'Cookie' => 'monster'})
46
+ .to_return(:status => 200, :headers => {'location' => 'https://live.bullionvault.com/secure/surprise.do'})
47
+
48
+ @client.send(:login).should be_false
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe BullionVault::Client::ViewBalance do
4
+ before(:each) do
5
+ @client = BullionVault::Client.new(:cookie => 'monster')
6
+ end
7
+
8
+ describe '#view_market' do
9
+ it 'gets market offers' do
10
+ stub_request(:get, 'https://live.bullionvault.com/view_market_xml.do')
11
+ .with(:headers => {'Cookie' => 'monster'})
12
+ .to_return(:status => 200, :body => fixture('view_balance.xml'))
13
+
14
+ @client.view_market.should eq yaml_fixture('view_balance.yaml')
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe BullionVault::Client::ViewMarket do
4
+ before(:each) do
5
+ @client = BullionVault::Client.new
6
+ end
7
+
8
+ describe '#view_market' do
9
+ it 'gets market offers' do
10
+ stub_request(:get, 'https://live.bullionvault.com/view_market_xml.do')
11
+ .to_return(:status => 200, :body => fixture('view_market.xml'))
12
+
13
+ @client.view_market.should eq yaml_fixture('view_market.yaml')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe BullionVault::Client do
4
+ before(:each) do
5
+ @client = BullionVault::Client.new
6
+ end
7
+
8
+ it 'connects to the endpoint configuration' do
9
+ endpoint = URI.parse(@client.api_endpoint).to_s
10
+ connection = @client.send(:connection).build_url(nil).to_s
11
+ connection.should == endpoint
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'spec_helper'
3
+
4
+ describe BullionVault do
5
+ after do
6
+ BullionVault.reset
7
+ end
8
+
9
+ context 'when delegating to a client' do
10
+ before do
11
+ stub_request(:get, 'https://live.bullionvault.com/view_market_xml.do')
12
+ .to_return(:body => fixture('view_market.xml'))
13
+ end
14
+
15
+ it 'gets the correct resource' do
16
+ BullionVault.view_market
17
+ a_request(:get, 'https://live.bullionvault.com/view_market_xml.do')
18
+ .should have_been_made
19
+ end
20
+
21
+ it 'returns the same results as a client' do
22
+ BullionVault.view_market.should == BullionVault::Client.new.view_market
23
+ end
24
+ end
25
+
26
+ describe '.client' do
27
+ it 'is a BullionVault::Client' do
28
+ BullionVault.client.should be_a BullionVault::Client
29
+ end
30
+ end
31
+
32
+ OPTIONS_KEYS = %w{adapter user_login user_password endpoint format proxy cookie user_agent}
33
+
34
+ describe 'VALID_OPTIONS_KEYS' do
35
+ it 'matches the list in the spec' do
36
+ OPTIONS_KEYS.map(&:to_sym).should eq BullionVault::Configuration::VALID_OPTIONS_KEYS
37
+ end
38
+ end
39
+
40
+ OPTIONS_KEYS.each do |key|
41
+ describe ".#{key}" do
42
+ it "returns the default #{key}" do
43
+ BullionVault.public_send(key).should eq BullionVault::Configuration.const_get("default_#{key}".upcase)
44
+ end
45
+ end
46
+
47
+ describe ".#{key}=" do
48
+ it "sets the #{key}" do
49
+ BullionVault.public_send("#{key}=", 'test_value')
50
+ BullionVault.public_send(key).should eq 'test_value'
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '.configure' do
56
+ BullionVault::Configuration::VALID_OPTIONS_KEYS.each do |key|
57
+ it "sets the #{key}" do
58
+ BullionVault.configure do |config|
59
+ config.public_send("#{key}=", key)
60
+ BullionVault.public_send(key).should == key
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Faraday::Request::CookieAuth do
4
+ before(:each) do
5
+ @client = BullionVault::Client.new(:cookie => 'monster')
6
+ end
7
+
8
+ it 'sets the cookie in requests' do
9
+ stub_request(:get, 'https://live.bullionvault.com/secure/login.do')
10
+ .with(:headers => {'Cookie' => 'monster'})
11
+ .to_return(:status => 200)
12
+ @client.get('secure/login.do', {}, true).should be_success
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Faraday::Response do
4
+ before do
5
+ @client = BullionVault::Client.new
6
+ end
7
+
8
+ context 'when the cookie is set' do
9
+ it 'raises InvalidCookieError' do
10
+ stub_request(:get, 'https://live.bullionvault.com/action.do')
11
+ .to_return(:status => 200, :headers => {'set-cookie' => 'monster'})
12
+
13
+ @client.cookie = 'illegitimate_value'
14
+ proc { @client.get('action.do') }.should raise_error(BullionVault::InvalidCookie)
15
+ end
16
+ end
17
+
18
+ {
19
+ 400 => BullionVault::BadRequest,
20
+ 401 => BullionVault::Unauthorized,
21
+ 403 => BullionVault::Forbidden,
22
+ 404 => BullionVault::NotFound,
23
+ 406 => BullionVault::NotAcceptable,
24
+ 500 => BullionVault::InternalServerError,
25
+ 502 => BullionVault::BadGateway,
26
+ 503 => BullionVault::ServiceUnavailable,
27
+ }.each do |status, exception|
28
+ context "when HTTP status is #{status}" do
29
+
30
+ before do
31
+ stub_request(:get, 'https://live.bullionvault.com/error_inducing_action.do')
32
+ .to_return(:status => status)
33
+ end
34
+
35
+ it "raises #{exception.name} error" do
36
+ proc { @client.get('error_inducing_action.do') }.should raise_error(exception)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ <?xml version="1.0"?>
2
+ <envelope>
3
+ <message type="CLIENT_BALANCE_A" version="0.2">
4
+ <clientBalance>
5
+ <clientPositions>
6
+ <clientPosition
7
+ securityId="USD"
8
+ available="101"
9
+ total="101"
10
+ classNarrative="CURRENCY"
11
+ totalValuation="101"
12
+ valuationCurrency="USD"
13
+ />
14
+ <clientPosition
15
+ securityId="GBP"
16
+ available="1"
17
+ total="1"
18
+ classNarrative="CURRENCY"
19
+ totalValuation="1.61"
20
+ valuationCurrency="USD"
21
+ />
22
+ <clientPosition
23
+ securityId="EUR"
24
+ available="1"
25
+ total="1"
26
+ classNarrative="CURRENCY"
27
+ totalValuation="1.43"
28
+ valuationCurrency="USD"
29
+ />
30
+ <clientPosition
31
+ securityId="AUXZU"
32
+ available="0.001"
33
+ total="0.001"
34
+ classNarrative="GOLD"
35
+ totalValuation="45.95"
36
+ valuationCurrency="USD"
37
+ />
38
+ </clientPositions>
39
+ </clientBalance>
40
+ </message>
41
+ </envelope>