bullion_vault 0.1.0

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.
@@ -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>