agiley-faraday_middleware 0.8.3.2 → 0.9.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.
Files changed (40) hide show
  1. data/.gitignore +2 -2
  2. data/.rspec +2 -1
  3. data/.travis.yml +6 -3
  4. data/Gemfile +5 -1
  5. data/Rakefile +16 -4
  6. data/faraday_middleware.gemspec +1 -1
  7. data/lib/faraday_middleware.rb +17 -13
  8. data/lib/faraday_middleware/instrumentation.rb +2 -2
  9. data/lib/faraday_middleware/rack_compatible.rb +14 -9
  10. data/lib/faraday_middleware/request/encode_json.rb +4 -2
  11. data/lib/faraday_middleware/request/method_override.rb +51 -0
  12. data/lib/faraday_middleware/request/oauth.rb +28 -5
  13. data/lib/faraday_middleware/response/caching.rb +7 -2
  14. data/lib/faraday_middleware/response/chunked.rb +29 -0
  15. data/lib/faraday_middleware/response/follow_redirects.rb +100 -11
  16. data/lib/faraday_middleware/response/mashify.rb +11 -2
  17. data/lib/faraday_middleware/response/parse_dates.rb +39 -0
  18. data/lib/faraday_middleware/response/parse_json.rb +17 -5
  19. data/lib/faraday_middleware/response/parse_marshal.rb +2 -2
  20. data/lib/faraday_middleware/response/parse_xml.rb +3 -2
  21. data/lib/faraday_middleware/response/parse_yaml.rb +3 -1
  22. data/lib/faraday_middleware/response/rashify.rb +2 -0
  23. data/lib/faraday_middleware/response_middleware.rb +2 -2
  24. data/lib/faraday_middleware/version.rb +1 -1
  25. data/spec/caching_test.rb +37 -4
  26. data/spec/chunked_spec.rb +78 -0
  27. data/spec/encode_json_spec.rb +13 -13
  28. data/spec/follow_redirects_spec.rb +203 -18
  29. data/spec/helper.rb +15 -1
  30. data/spec/mashify_spec.rb +46 -26
  31. data/spec/method_override_spec.rb +92 -0
  32. data/spec/oauth2_spec.rb +18 -18
  33. data/spec/oauth_spec.rb +67 -17
  34. data/spec/parse_dates_spec.rb +39 -0
  35. data/spec/parse_json_spec.rb +37 -19
  36. data/spec/parse_marshal_spec.rb +3 -3
  37. data/spec/parse_xml_spec.rb +13 -13
  38. data/spec/parse_yaml_spec.rb +10 -10
  39. data/spec/rashify_spec.rb +26 -23
  40. metadata +78 -21
@@ -1,5 +1,15 @@
1
1
  if ENV['COVERAGE']
2
2
  require 'simplecov'
3
+
4
+ SimpleCov.formatter = Class.new do
5
+ def format(result)
6
+ SimpleCov::Formatter::HTMLFormatter.new.format(result) unless ENV['CI']
7
+ File.open('coverage/covered_percent', 'w') do |f|
8
+ f.puts result.source_files.covered_percent.to_i
9
+ end
10
+ end
11
+ end
12
+
3
13
  SimpleCov.start do
4
14
  # add_filter 'faraday_middleware.rb'
5
15
  add_filter 'backwards_compatibility.rb'
@@ -11,6 +21,7 @@ require 'rspec'
11
21
  module ResponseMiddlewareExampleGroup
12
22
  def self.included(base)
13
23
  base.let(:options) { Hash.new }
24
+ base.let(:headers) { Hash.new }
14
25
  base.let(:middleware) {
15
26
  described_class.new(lambda {|env|
16
27
  Faraday::Response.new(env)
@@ -21,7 +32,7 @@ module ResponseMiddlewareExampleGroup
21
32
  def process(body, content_type = nil, options = {})
22
33
  env = {
23
34
  :body => body, :request => options,
24
- :response_headers => Faraday::Utils::Headers.new
35
+ :response_headers => Faraday::Utils::Headers.new(headers)
25
36
  }
26
37
  env[:response_headers]['content-type'] = content_type if content_type
27
38
  middleware.call(env)
@@ -30,4 +41,7 @@ end
30
41
 
31
42
  RSpec.configure do |config|
32
43
  config.include ResponseMiddlewareExampleGroup, :type => :response
44
+ config.expect_with :rspec do |c|
45
+ c.syntax = :expect
46
+ end
33
47
  end
@@ -2,63 +2,80 @@ require 'helper'
2
2
  require 'faraday_middleware/response/mashify'
3
3
 
4
4
  describe FaradayMiddleware::Mashify do
5
- context 'during configuration' do
6
- it 'should allow for a custom Mash class to be set' do
7
- described_class.should respond_to(:mash_class)
8
- described_class.should respond_to(:mash_class=)
5
+ context "during configuration" do
6
+ it "allows for a custom Mash class to be set" do
7
+ expect(described_class).to respond_to(:mash_class)
8
+ expect(described_class).to respond_to(:mash_class=)
9
9
  end
10
10
  end
11
11
 
12
- context 'when used' do
12
+ context "when used" do
13
13
  before(:each) { described_class.mash_class = ::Hashie::Mash }
14
14
  let(:mashify) { described_class.new }
15
15
 
16
- it 'should create a Hashie::Mash from the body' do
16
+ it "creates a Hashie::Mash from the body" do
17
17
  env = { :body => { "name" => "Erik Michaels-Ober", "username" => "sferik" } }
18
18
  me = mashify.on_complete(env)
19
- me.class.should == Hashie::Mash
19
+ expect(me.class).to eq(Hashie::Mash)
20
20
  end
21
21
 
22
- it 'should handle strings' do
22
+ it "handles strings" do
23
23
  env = { :body => "Most amazing string EVER" }
24
24
  me = mashify.on_complete(env)
25
- me.should == "Most amazing string EVER"
25
+ expect(me).to eq("Most amazing string EVER")
26
26
  end
27
27
 
28
- it 'should handle arrays' do
28
+ it "handles arrays" do
29
29
  env = { :body => [123, 456] }
30
30
  values = mashify.on_complete(env)
31
- values.first.should == 123
32
- values.last.should == 456
31
+ expect(values.first).to eq(123)
32
+ expect(values.last).to eq(456)
33
33
  end
34
34
 
35
- it 'should handle arrays of hashes' do
35
+ it "handles arrays of hashes" do
36
36
  env = { :body => [{ "username" => "sferik" }, { "username" => "pengwynn" }] }
37
37
  us = mashify.on_complete(env)
38
- us.first.username.should == 'sferik'
39
- us.last.username.should == 'pengwynn'
38
+ expect(us.first.username).to eq('sferik')
39
+ expect(us.last.username).to eq('pengwynn')
40
40
  end
41
41
 
42
- it 'should handle mixed arrays' do
42
+ it "handles nested arrays of hashes" do
43
+ env = { :body => [[{ "username" => "sferik" }, { "username" => "pengwynn" }]] }
44
+ us = mashify.on_complete(env)
45
+ expect(us.first.first.username).to eq('sferik')
46
+ expect(us.first.last.username).to eq('pengwynn')
47
+ end
48
+
49
+ it "handles mixed arrays" do
43
50
  env = { :body => [123, { "username" => "sferik" }, 456] }
44
51
  values = mashify.on_complete(env)
45
- values.first.should == 123
46
- values.last.should == 456
47
- values[1].username.should == 'sferik'
52
+ expect(values.first).to eq(123)
53
+ expect(values.last).to eq(456)
54
+ expect(values[1].username).to eq('sferik')
48
55
  end
49
56
 
50
- it 'should allow for use of custom Mash subclasses' do
57
+ it "allows for use of custom Mash subclasses at the class level" do
51
58
  class MyMash < ::Hashie::Mash; end
52
59
  described_class.mash_class = MyMash
53
60
 
54
61
  env = { :body => { "name" => "Erik Michaels-Ober", "username" => "sferik" } }
55
62
  me = mashify.on_complete(env)
56
63
 
57
- me.class.should == MyMash
64
+ expect(me.class).to eq(MyMash)
65
+ end
66
+
67
+ it "allows for use of custom Mash subclasses at the instance level" do
68
+ class MyMash < ::Hashie::Mash; end
69
+ mashify = described_class.new(nil, :mash_class => MyMash)
70
+
71
+ env = { :body => { "name" => "Erik Michaels-Ober", "username" => "sferik" } }
72
+ me = mashify.on_complete(env)
73
+
74
+ expect(me.class).to eq(MyMash)
58
75
  end
59
76
  end
60
77
 
61
- context 'integration test' do
78
+ context "integration test" do
62
79
  let(:stubs) { Faraday::Adapter::Test::Stubs.new }
63
80
  let(:connection) do
64
81
  Faraday::Connection.new do |builder|
@@ -69,11 +86,14 @@ describe FaradayMiddleware::Mashify do
69
86
 
70
87
  # although it is not good practice to pass a hash as the body, if we add ParseJson
71
88
  # to the middleware stack we end up testing two middlewares instead of one
72
- it 'should create a Hash from the body' do
73
- stubs.get('/hash') {[200, {'content-type' => 'application/json; charset=utf-8'}, { "name" => "Erik Michaels-Ober", "username" => "sferik" }]}
89
+ it "creates a Hash from the body" do
90
+ stubs.get('/hash') {
91
+ data = { 'name' => 'Erik Michaels-Ober', 'username' => 'sferik' }
92
+ [200, {'content-type' => 'application/json; charset=utf-8'}, data]
93
+ }
74
94
  me = connection.get('/hash').body
75
- me.name.should == 'Erik Michaels-Ober'
76
- me.username.should == 'sferik'
95
+ expect(me.name).to eq('Erik Michaels-Ober')
96
+ expect(me.username).to eq('sferik')
77
97
  end
78
98
  end
79
99
  end
@@ -0,0 +1,92 @@
1
+ require 'helper'
2
+ require 'faraday_middleware/request/method_override'
3
+
4
+ describe FaradayMiddleware::MethodOverride do
5
+
6
+ let(:middleware) { described_class.new(lambda {|env| env }, *options) }
7
+ let(:env) { middleware.call request_env(request_method) }
8
+
9
+ def request_env(method)
10
+ { :method => method,
11
+ :request_headers => Faraday::Utils::Headers.new
12
+ }
13
+ end
14
+
15
+ shared_examples "overrides method" do |method|
16
+ it "sets physical method to POST" do
17
+ expect(env[:method]).to eq(:post)
18
+ end
19
+
20
+ it "sets header to #{method}" do
21
+ expect(env[:request_headers]['X-Http-Method-Override']).to eq(method)
22
+ end
23
+ end
24
+
25
+ shared_examples "doesn't override method" do |method|
26
+ it "keeps original method" do
27
+ expect(env[:method]).to eq(method)
28
+ end
29
+
30
+ it "doesn't set header value" do
31
+ expect(env[:request_headers]).not_to have_key('X-Http-Method-Override')
32
+ end
33
+
34
+ end
35
+
36
+ context "with default options" do
37
+ let(:options) { nil }
38
+
39
+ context "GET" do
40
+ let(:request_method) { :get }
41
+ include_examples "doesn't override method", :get
42
+ end
43
+
44
+ context "POST" do
45
+ let(:request_method) { :post }
46
+ include_examples "doesn't override method", :post
47
+ end
48
+
49
+ context "PUT" do
50
+ let(:request_method) { :put }
51
+ include_examples "overrides method", 'PUT'
52
+ end
53
+ end
54
+
55
+ context "configured to rewrite [:patch, :delete]" do
56
+ let(:options) { [{ :rewrite => [:patch, :delete] }] }
57
+
58
+ context "PUT" do
59
+ let(:request_method) { :put }
60
+ include_examples "doesn't override method", :put
61
+ end
62
+
63
+ context "PATCH" do
64
+ let(:request_method) { :patch }
65
+ include_examples "overrides method", 'PATCH'
66
+ end
67
+
68
+ context "DELETE" do
69
+ let(:request_method) { :delete }
70
+ include_examples "overrides method", 'DELETE'
71
+ end
72
+ end
73
+
74
+ context "configured to rewrite ['PATCH']" do
75
+ let(:options) { [{ :rewrite => %w[PATCH] }] }
76
+
77
+ context "PATCH" do
78
+ let(:request_method) { :patch }
79
+ include_examples "overrides method", 'PATCH'
80
+ end
81
+ end
82
+
83
+ context "with invalid option" do
84
+ let(:options) { [{ :hello => 'world' }] }
85
+ let(:request_method) { :get }
86
+
87
+ it "raises key error" do
88
+ expect{ env }.to raise_error(IndexError, /key not found/)
89
+ end
90
+ end
91
+
92
+ end
@@ -31,17 +31,17 @@ describe FaradayMiddleware::OAuth2 do
31
31
 
32
32
  it "doesn't add params" do
33
33
  request = perform(:q => 'hello')
34
- query_params(request).should eq('q' => 'hello')
34
+ expect(query_params(request)).to eq('q' => 'hello')
35
35
  end
36
36
 
37
37
  it "doesn't add headers" do
38
- auth_header(perform).should be_nil
38
+ expect(auth_header(perform)).to be_nil
39
39
  end
40
40
 
41
41
  it "creates header for explicit token" do
42
42
  request = perform(:q => 'hello', :access_token => 'abc123')
43
- query_params(request).should eq('q' => 'hello', 'access_token' => 'abc123')
44
- auth_header(request).should eq(%(Token token="abc123"))
43
+ expect(query_params(request)).to eq('q' => 'hello', 'access_token' => 'abc123')
44
+ expect(auth_header(request)).to eq(%(Token token="abc123"))
45
45
  end
46
46
  end
47
47
 
@@ -49,23 +49,23 @@ describe FaradayMiddleware::OAuth2 do
49
49
  let(:options) { 'XYZ' }
50
50
 
51
51
  it "adds token param" do
52
- query_params(perform(:q => 'hello')).should eq('q' => 'hello', 'access_token' => 'XYZ')
52
+ expect(query_params(perform(:q => 'hello'))).to eq('q' => 'hello', 'access_token' => 'XYZ')
53
53
  end
54
54
 
55
55
  it "adds token header" do
56
- auth_header(perform).should eq(%(Token token="XYZ"))
56
+ expect(auth_header(perform)).to eq(%(Token token="XYZ"))
57
57
  end
58
58
 
59
59
  it "overrides default with explicit token" do
60
60
  request = perform(:q => 'hello', :access_token => 'abc123')
61
- query_params(request).should eq('q' => 'hello', 'access_token' => 'abc123')
62
- auth_header(request).should eq(%(Token token="abc123"))
61
+ expect(query_params(request)).to eq('q' => 'hello', 'access_token' => 'abc123')
62
+ expect(auth_header(request)).to eq(%(Token token="abc123"))
63
63
  end
64
64
 
65
65
  it "clears default with empty explicit token" do
66
66
  request = perform(:q => 'hello', :access_token => nil)
67
- query_params(request).should eq('q' => 'hello', 'access_token' => nil)
68
- auth_header(request).should be_nil
67
+ expect(query_params(request)).to eq('q' => 'hello', 'access_token' => nil)
68
+ expect(auth_header(request)).to be_nil
69
69
  end
70
70
  end
71
71
 
@@ -74,11 +74,11 @@ describe FaradayMiddleware::OAuth2 do
74
74
  subject { perform({:q => 'hello'}, 'Authorization' => 'custom') }
75
75
 
76
76
  it "adds token param" do
77
- query_params(subject).should eq('q' => 'hello', 'access_token' => 'XYZ')
77
+ expect(query_params(subject)).to eq('q' => 'hello', 'access_token' => 'XYZ')
78
78
  end
79
79
 
80
80
  it "doesn't override existing header" do
81
- auth_header(subject).should eq('custom')
81
+ expect(auth_header(subject)).to eq('custom')
82
82
  end
83
83
  end
84
84
 
@@ -86,13 +86,13 @@ describe FaradayMiddleware::OAuth2 do
86
86
  let(:options) { ['XYZ', {:param_name => :oauth}] }
87
87
 
88
88
  it "adds token param" do
89
- query_params(perform).should eq('oauth' => 'XYZ')
89
+ expect(query_params(perform)).to eq('oauth' => 'XYZ')
90
90
  end
91
91
 
92
92
  it "overrides default with explicit token" do
93
93
  request = perform(:oauth => 'abc123')
94
- query_params(request).should eq('oauth' => 'abc123')
95
- auth_header(request).should eq(%(Token token="abc123"))
94
+ expect(query_params(request)).to eq('oauth' => 'abc123')
95
+ expect(auth_header(request)).to eq(%(Token token="abc123"))
96
96
  end
97
97
  end
98
98
 
@@ -100,11 +100,11 @@ describe FaradayMiddleware::OAuth2 do
100
100
  let(:options) { [{:param_name => :oauth}] }
101
101
 
102
102
  it "doesn't add param" do
103
- query_params(perform).should be_empty
103
+ expect(query_params(perform)).to be_empty
104
104
  end
105
105
 
106
106
  it "overrides default with explicit token" do
107
- query_params(perform(:oauth => 'abc123')).should eq('oauth' => 'abc123')
107
+ expect(query_params(perform(:oauth => 'abc123'))).to eq('oauth' => 'abc123')
108
108
  end
109
109
  end
110
110
 
@@ -112,7 +112,7 @@ describe FaradayMiddleware::OAuth2 do
112
112
  let(:options) { ['XYZ', {:param_name => nil}] }
113
113
 
114
114
  it "raises error" do
115
- expect { make_app }.to raise_error(ArgumentError, ":param_name can't be blank")
115
+ expect{ make_app }.to raise_error(ArgumentError, ":param_name can't be blank")
116
116
  end
117
117
  end
118
118
  end
@@ -1,6 +1,7 @@
1
1
  require 'helper'
2
2
  require 'faraday_middleware/request/oauth'
3
3
  require 'uri'
4
+ require 'forwardable'
4
5
 
5
6
  describe FaradayMiddleware::OAuth do
6
7
  def auth_header(env)
@@ -14,11 +15,12 @@ describe FaradayMiddleware::OAuth do
14
15
  end
15
16
  end
16
17
 
17
- def perform(oauth_options = {}, headers = {})
18
+ def perform(oauth_options = {}, headers = {}, params = {})
18
19
  env = {
19
20
  :url => URI('http://example.com/'),
20
21
  :request_headers => Faraday::Utils::Headers.new.update(headers),
21
- :request => {}
22
+ :request => {},
23
+ :body => params
22
24
  }
23
25
  unless oauth_options.is_a? Hash and oauth_options.empty?
24
26
  env[:request][:oauth] = oauth_options
@@ -34,21 +36,21 @@ describe FaradayMiddleware::OAuth do
34
36
  context "invalid options" do
35
37
  let(:options) { nil }
36
38
 
37
- it "should error out" do
38
- expect { make_app }.to raise_error(ArgumentError)
39
+ it "errors out" do
40
+ expect{ make_app }.to raise_error(ArgumentError)
39
41
  end
40
42
  end
41
43
 
42
44
  context "empty options" do
43
45
  let(:options) { [{}] }
44
46
 
45
- it "should sign request" do
47
+ it "signs request" do
46
48
  auth = auth_values(perform)
47
49
  expected_keys = %w[ oauth_nonce
48
50
  oauth_signature oauth_signature_method
49
51
  oauth_timestamp oauth_version ]
50
52
 
51
- auth.keys.should =~ expected_keys
53
+ expect(auth.keys).to match_array expected_keys
52
54
  end
53
55
  end
54
56
 
@@ -65,27 +67,27 @@ describe FaradayMiddleware::OAuth do
65
67
  oauth_signature oauth_signature_method
66
68
  oauth_timestamp oauth_token oauth_version ]
67
69
 
68
- auth.keys.should =~ expected_keys
69
- auth['oauth_version'].should eq(%("1.0"))
70
- auth['oauth_signature_method'].should eq(%("HMAC-SHA1"))
71
- auth['oauth_consumer_key'].should eq(%("CKEY"))
72
- auth['oauth_token'].should eq(%("TOKEN"))
70
+ expect(auth.keys).to match_array expected_keys
71
+ expect(auth['oauth_version']).to eq(%("1.0"))
72
+ expect(auth['oauth_signature_method']).to eq(%("HMAC-SHA1"))
73
+ expect(auth['oauth_consumer_key']).to eq(%("CKEY"))
74
+ expect(auth['oauth_token']).to eq(%("TOKEN"))
73
75
  end
74
76
 
75
77
  it "doesn't override existing header" do
76
78
  request = perform({}, "Authorization" => "iz me!")
77
- auth_header(request).should eq("iz me!")
79
+ expect(auth_header(request)).to eq("iz me!")
78
80
  end
79
81
 
80
82
  it "can override oauth options per-request" do
81
83
  auth = auth_values(perform(:consumer_key => 'CKEY2'))
82
84
 
83
- auth['oauth_consumer_key'].should eq(%("CKEY2"))
84
- auth['oauth_token'].should eq(%("TOKEN"))
85
+ expect(auth['oauth_consumer_key']).to eq(%("CKEY2"))
86
+ expect(auth['oauth_token']).to eq(%("TOKEN"))
85
87
  end
86
88
 
87
89
  it "can turn off oauth signing per-request" do
88
- auth_header(perform(false)).should be_nil
90
+ expect(auth_header(perform(false))).to be_nil
89
91
  end
90
92
  end
91
93
 
@@ -94,8 +96,56 @@ describe FaradayMiddleware::OAuth do
94
96
 
95
97
  it "adds auth info to the header" do
96
98
  auth = auth_values(perform)
97
- auth.should include('oauth_consumer_key')
98
- auth.should_not include('oauth_token')
99
+ expect(auth).to include('oauth_consumer_key')
100
+ expect(auth).not_to include('oauth_token')
99
101
  end
100
102
  end
103
+
104
+ context "handling body parameters" do
105
+ let(:options) { [{ :consumer_key => 'CKEY',
106
+ :consumer_secret => 'CSECRET',
107
+ :nonce => '547fed103e122eecf84c080843eedfe6',
108
+ :timestamp => '1286830180'}] }
109
+
110
+ let(:value) { {'foo' => 'bar'} }
111
+
112
+ let(:type_json) { {'Content-Type' => 'application/json'} }
113
+ let(:type_form) { {'Content-Type' => 'application/x-www-form-urlencoded'} }
114
+
115
+ extend Forwardable
116
+ query_method = :build_nested_query
117
+ query_module = ::Faraday::Utils.respond_to?(query_method) ? 'Faraday::Utils' : 'Rack::Utils'
118
+ def_delegator query_module, query_method
119
+
120
+ it "does not include the body for JSON" do
121
+ auth_header_with = auth_header(perform({}, type_json, '{"foo":"bar"}'))
122
+ auth_header_without = auth_header(perform({}, type_json, {}))
123
+
124
+ expect(auth_header_with).to eq(auth_header_without)
125
+ end
126
+
127
+ it "includes the body parameters with form Content-Type" do
128
+ auth_header_with = auth_header(perform({}, type_form, {}))
129
+ auth_header_without = auth_header(perform({}, type_form, value))
130
+
131
+ expect(auth_header_with).not_to eq(auth_header_without)
132
+ end
133
+
134
+ it "includes the body parameters with an unspecified Content-Type" do
135
+ auth_header_with = auth_header(perform({}, {}, value))
136
+ auth_header_without = auth_header(perform({}, type_form, value))
137
+
138
+ expect(auth_header_with).to eq(auth_header_without)
139
+ end
140
+
141
+ it "includes the body parameters for form type with string body" do
142
+ # simulates the behavior of Faraday::MiddleWare::UrlEncoded
143
+ value = { 'foo' => ['bar', 'baz', 'wat'] }
144
+ auth_header_hash = auth_header(perform({}, type_form, value))
145
+ auth_header_string = auth_header(perform({}, type_form, build_nested_query(value)))
146
+ expect(auth_header_string).to eq(auth_header_hash)
147
+ end
148
+
149
+ end
150
+
101
151
  end