pact-support 0.5.5 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8302de9af32aa569443e49a502132233ecc0fbc6
4
- data.tar.gz: d03296b6197757a59b1a8c197b375fb17e3be7d7
3
+ metadata.gz: 8eeb1140d12c89f3c03f855ecfbb9666259b502c
4
+ data.tar.gz: 8b7e7ef1dea78d0abe77c2fb0db5a17f46ee47e9
5
5
  SHA512:
6
- metadata.gz: db57a82df74f57807f6514abad63b30374ebbb81d6aadac107059e9dbef23978d2e94ef2b6a5c30095d5b870a464aea05269bea1ffa96aa030305a2d595c546a
7
- data.tar.gz: 9918d2bd33d4986bfcf67e41ed2a52d1d216bff694df1035f666cef2a933fbaaef37e8d5f82b9d34c3f80b5fab3a6c6434db6e06c15fc01a982bac5bf6f435da
6
+ metadata.gz: 9cbde3f5574d69c3be0b1e8f2fa7cd196e4c2e42133e966a7087d8a4f3796cb21906c93c7d6df5b97a445842031ed713ab1fa96de44f20110a25d3655e64fb49
7
+ data.tar.gz: 09d6fc96eeb2c6fcdce7269392a47a08ba3efa50e927b2fc80e9d41a21197dd4d1e37826ebe211b81ca9c79ad019761462431243385f7a34ff2514414314f71c
@@ -3,5 +3,5 @@ rvm:
3
3
  - 2.0.0
4
4
  - 2.1.8
5
5
  - 2.2.4
6
- - 2.3.0
6
+ - 2.3.1
7
7
  - jruby-9.0.5.0
@@ -2,20 +2,23 @@ Do this to generate your change history
2
2
 
3
3
  git log --pretty=format:' * %h - %s (%an, %ad)' vX.Y.Z..HEAD
4
4
 
5
-
6
- ### 0.5.5 (4 November 2015)
7
- * e9aaff0 - Merge pull request #21 from TakatoshiMaeda/reify_support_nested_something_like (Sergei Matheson, Fri Apr 29 09:54:00 2016 +1000)
5
+ ### 0.5.7 (3 May 2016)
6
+ * 289d4e5 - Handle loading local pact files as well as remote (Sergei Matheson, Tue May 3 12:56:51 2016 +1000)
7
+ * 6d4e559 - Update to ruby 2.3.1 in travis (Sergei Matheson, Tue May 3 10:46:46 2016 +1000)
8
+
9
+ ### 0.5.6 (29 April 2016)
10
+ * d8bc8fa - Remove pull request merge logs from changelog (Sergei Matheson, Fri Apr 29 10:06:51 2016 +1000)
11
+ * 24ba197 - Corrected v0.5.5 release date in CHANGELOG (Sergei Matheson, Fri Apr 29 10:05:11 2016 +1000)
12
+ * 9dcef8d - Retry reading pact file (Taiki Ono, Thu Apr 28 17:15:54 2016 +0900)
13
+ * 61ceda1 - Re-write test with WebMock (Taiki Ono, Thu Apr 28 15:50:29 2016 +0900)
14
+ * 62dcf66 - Use WebMock2 (Taiki Ono, Thu Apr 28 13:51:53 2016 +0900)
15
+
16
+ ### 0.5.5 (29 April 2016)
8
17
  * eb9aa26 - Supporting nested Pact::SomethingLike reification (Takatoshi Maeda, Thu Apr 28 02:04:58 2016 +0900)
9
- * 832790d - Merge pull request #20 from taiki45/dsl-without-block (Sergei Matheson, Thu Mar 24 09:36:22 2016 +1100)
10
18
  * 9e924c8 - Object supporting DSL can be built without block (Taiki Ono, Wed Mar 23 16:38:27 2016 +0900)
11
- * 57aa993 - Merge pull request #18 from taiki45/escape-query-string-component (Sergei Matheson, Tue Mar 15 09:24:36 2016 +1100)
12
19
  * 2b0e7b4 - Escape query string components (Taiki Ono, Mon Mar 14 15:22:29 2016 +0900)
13
20
  * a383368 - Fix indent (Taiki Ono, Mon Mar 14 15:18:26 2016 +0900)
14
- * fae9a14 - Merge pull request #17 from taiki45/upgrade-jruby (Ronald Holshausen, Mon Mar 14 09:56:16 2016 +1100)
15
21
  * dc54092 - Support latest jruby and drop supporting jruby 1.7 (Taiki Ono, Sun Mar 13 20:27:17 2016 +0900)
16
- * 22651e8 - Merge pull request #16 from taiki45/drop-supporting-ruby1.9 (Beth Skurrie, Sat Mar 12 14:04:41 2016 +1100)
17
- * 3dbaa38 - Merge pull request #15 from taiki45/suppress-rspec-warnings (Sergei Matheson, Fri Mar 11 09:29:26 2016 +1100)
18
- * 656c98a - Merge pull request #14 from taiki45/nested-query (Sergei Matheson, Fri Mar 11 09:19:58 2016 +1100)
19
22
  * 85fbb09 - Drop supporting ruby1.9 (Taiki Ono, Thu Mar 10 23:01:54 2016 +0900)
20
23
  * 966fa3a - `raise_error` should be with specific error (Taiki Ono, Thu Mar 10 22:50:13 2016 +0900)
21
24
  * 2861742 - Cosmetic change (Taiki Ono, Thu Mar 10 22:11:51 2016 +0900)
@@ -1,9 +1,22 @@
1
- module Pact
1
+ require 'net/http'
2
2
 
3
+ module Pact
3
4
  module PactFile
4
-
5
5
  extend self
6
6
 
7
+ OPEN_TIMEOUT = 5
8
+ READ_TIMEOUT = 5
9
+ RETRY_LIMIT = 3
10
+
11
+ class HttpError < StandardError
12
+ attr_reader :uri, :response
13
+
14
+ def initialize(uri, response)
15
+ @uri, @response = uri, response
16
+ super("HTTP request failed: status=#{response.code}")
17
+ end
18
+ end
19
+
7
20
  def read uri, options = {}
8
21
  uri_string = uri.to_s
9
22
  pact = render_pact(uri_string, options)
@@ -22,16 +35,74 @@ module Pact
22
35
  ::File.open(Pact.configuration.tmp_dir + "/#{name}", "w") { |file| file << pact}
23
36
  end
24
37
 
25
- def render_pact uri_string, options
38
+ def render_pact(uri_string, options)
26
39
  uri_obj = URI(uri_string)
27
- uri_user_info = uri_obj.userinfo
28
- if(uri_user_info)
40
+ if uri_obj.userinfo
29
41
  options[:username] = uri_obj.user unless options[:username]
30
42
  options[:password] = uri_obj.password unless options[:password]
31
- uri_string = uri_string.sub("#{uri_user_info}@", '')
32
43
  end
33
- open_options = options[:username] ? {http_basic_authentication:[options[:username],options[:password]]} : {}
34
- open(uri_string, open_options) { | file | file.read }
44
+ get(uri_obj, options)
45
+ end
46
+
47
+ private
48
+
49
+ def get(uri, options)
50
+ local?(uri) ? get_local(uri, options) : get_remote_with_retry(uri, options)
51
+ end
52
+
53
+ def local? uri
54
+ !uri.host
55
+ end
56
+
57
+ def get_local(uri, _)
58
+ File.read uri.to_s
59
+ end
60
+
61
+ def get_remote(uri, options)
62
+ request = Net::HTTP::Get.new(uri)
63
+ request.basic_auth(options[:username], options[:password]) if options[:username]
64
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
65
+ http.open_timeout = options[:open_timeout] || OPEN_TIMEOUT
66
+ http.read_timeout = options[:read_timeout] || READ_TIMEOUT
67
+ http.request(request)
68
+ end
69
+ end
70
+
71
+ def get_remote_with_retry(uri, options)
72
+ ((options[:retry_limit] || RETRY_LIMIT) + 1).times do |i|
73
+ begin
74
+ response = get_remote(uri, options)
75
+ case
76
+ when success?(response)
77
+ return response.body
78
+ when retryable?(response)
79
+ raise HttpError.new(uri, response) if abort_retry?(i, options)
80
+ delay_retry(i + 1)
81
+ next
82
+ else
83
+ raise HttpError.new(uri, response)
84
+ end
85
+ rescue Timeout::Error => e
86
+ raise e if abort_retry?(i, options)
87
+ delay_retry(i + 1)
88
+ end
89
+ end
90
+ end
91
+
92
+ def success?(response)
93
+ response.code.to_i == 200
94
+ end
95
+
96
+ def retryable?(response)
97
+ (500...600).cover?(response.code.to_i)
98
+ end
99
+
100
+ def abort_retry?(count, options)
101
+ count >= (options[:retry_limit] || RETRY_LIMIT)
102
+ end
103
+
104
+ def delay_retry(count)
105
+ Kernel.sleep(2 ** count * 0.3)
35
106
  end
36
107
  end
37
- end
108
+ end
@@ -1,5 +1,5 @@
1
1
  module Pact
2
2
  module Support
3
- VERSION = "0.5.5"
3
+ VERSION = "0.5.7"
4
4
  end
5
5
  end
@@ -27,7 +27,7 @@ Gem::Specification.new do |gem|
27
27
  gem.add_runtime_dependency 'thor'
28
28
 
29
29
  gem.add_development_dependency 'rake', '~> 10.0.3'
30
- gem.add_development_dependency 'webmock', '~> 1.18.0'
30
+ gem.add_development_dependency 'webmock', '~> 2.0.0'
31
31
  gem.add_development_dependency 'pry'
32
32
  gem.add_development_dependency 'fakefs', '~> 0.4'
33
33
  gem.add_development_dependency 'hashie', '~> 2.0'
@@ -1,14 +1,36 @@
1
1
  require 'spec_helper'
2
+ require 'tempfile'
2
3
  require 'pact/consumer_contract/pact_file'
4
+ require 'base64' # XXX: https://github.com/bblimke/webmock/pull/611
3
5
 
4
6
  module Pact
5
7
  describe PactFile do
6
8
  describe 'render_pact' do
7
9
  let(:uri_without_userinfo) { 'http://pactbroker.com'}
8
10
  let(:pact_content) { 'api contract'}
11
+
12
+ describe 'from a local file URI' do
13
+ let(:temp_file) { Tempfile.new('local-pact-file') }
14
+ let(:file_uri) { temp_file.path }
15
+ let(:local_pact_content) { 'local pact content' }
16
+ before do
17
+ File.write file_uri, local_pact_content
18
+ end
19
+ after do
20
+ temp_file.unlink
21
+ end
22
+
23
+ it 'reads from the local file system' do
24
+ expect(PactFile.render_pact(file_uri, {})).to eq(local_pact_content)
25
+ end
26
+ end
27
+
9
28
  context 'without basic authentication' do
29
+ before do
30
+ stub_request(:get, uri_without_userinfo).to_return(body: pact_content)
31
+ end
32
+
10
33
  it 'should open uri to get pact file content' do
11
- expect(PactFile).to receive(:open).with(uri_without_userinfo, {}).and_return(pact_content)
12
34
  expect(PactFile.render_pact(uri_without_userinfo, {})).to eq(pact_content)
13
35
  end
14
36
  end
@@ -19,29 +41,140 @@ module Pact
19
41
  let(:options) do
20
42
  { username: username, password: password }
21
43
  end
44
+ before do
45
+ stub_request(:get, uri_without_userinfo).with(basic_auth: [username, password]).to_return(body: pact_content)
46
+ end
47
+
22
48
  context 'when userinfo is specified in the option' do
23
49
  it 'should open uri to get pact file content with userinfo in the options' do
24
- expect(PactFile).to receive(:open).with(uri_without_userinfo, {http_basic_authentication:[username, password]})
25
- .and_return(pact_content)
26
50
  expect(PactFile.render_pact(uri_without_userinfo, options)).to eq(pact_content)
27
51
  end
52
+
28
53
  let(:uri_with_userinfo) { 'http://dummyuser:dummyps@pactbroker.com'}
54
+
29
55
  it 'should use userinfo in options which overwrites userinfo in url' do
30
- expect(PactFile).to receive(:open).with(uri_without_userinfo, {http_basic_authentication:[username, password]})
31
- .and_return(pact_content)
32
56
  expect(PactFile.render_pact(uri_with_userinfo, options)).to eq(pact_content)
33
57
  end
34
58
  end
35
59
 
36
60
  context 'when user info is specified in url' do
37
61
  let(:uri_with_userinfo) { "http://#{username}:#{password}@pactbroker.com"}
62
+
38
63
  it 'should open uri to get pact file content with userinfo in the uri' do
39
- expect(PactFile).to receive(:open).with(uri_without_userinfo, {http_basic_authentication:[username, password]})
40
- .and_return(pact_content)
41
64
  expect(PactFile.render_pact(uri_with_userinfo, {})).to eq(pact_content)
42
65
  end
43
66
  end
44
67
  end
68
+
69
+ describe 'retry feature' do
70
+ before { allow(PactFile).to receive(:delay_retry).with(kind_of(Integer)) }
71
+
72
+ def render_pact(options = {})
73
+ PactFile.render_pact(uri_without_userinfo, options)
74
+ end
75
+
76
+ context 'with client error' do
77
+ before { stub_request(:get, uri_without_userinfo).to_return(status: 400) }
78
+
79
+ it 'raises client error without retrying' do
80
+ expect(PactFile).not_to receive(:delay_retry)
81
+ expect { render_pact }.to raise_error(PactFile::HttpError, /status=400/)
82
+ end
83
+ end
84
+
85
+ context 'with single server error' do
86
+ before do
87
+ stub_request(:get, uri_without_userinfo).to_return(status: 500).
88
+ then.to_return(status: 200, body: pact_content)
89
+ end
90
+
91
+ it 'retries and succeeds' do
92
+ expect(render_pact).to eq(pact_content)
93
+ end
94
+ end
95
+
96
+ context 'with continuous server errors' do
97
+ before { stub_request(:get, uri_without_userinfo).to_return(status: 500) }
98
+
99
+ it 'retries but failed by retry limit' do
100
+ expect { render_pact }.to raise_error(PactFile::HttpError, /status=500/)
101
+ end
102
+ end
103
+
104
+ context 'with single open timeout' do
105
+ before do
106
+ stub_request(:get, uri_without_userinfo).to_raise(Net::OpenTimeout).
107
+ then.to_return(status: 200, body: pact_content)
108
+ end
109
+
110
+ it 'retries and succeeds' do
111
+ expect(render_pact).to eq(pact_content)
112
+ end
113
+ end
114
+
115
+ context 'with continuous open timeouts' do
116
+ before { stub_request(:get, uri_without_userinfo).to_raise(Net::OpenTimeout) }
117
+
118
+ it 'retries but failed by retry limit' do
119
+ expect { render_pact }.to raise_error(Net::OpenTimeout)
120
+ end
121
+ end
122
+
123
+ context 'with single read timeout' do
124
+ before do
125
+ stub_request(:get, uri_without_userinfo).to_raise(Net::ReadTimeout).
126
+ then.to_return(status: 200, body: pact_content)
127
+ end
128
+
129
+ it 'retries and succeeds' do
130
+ expect(render_pact).to eq(pact_content)
131
+ end
132
+ end
133
+
134
+ context 'with continuous read timeout' do
135
+ before { stub_request(:get, uri_without_userinfo).to_raise(Net::ReadTimeout) }
136
+
137
+ it 'retries but failed by retry limit' do
138
+ expect { render_pact }.to raise_error(Net::ReadTimeout)
139
+ end
140
+ end
141
+
142
+ context 'with retry_limit option and server error' do
143
+ before do
144
+ stub_request(:get, uri_without_userinfo).to_return(status: 500).
145
+ then.to_return(status: 200, body: pact_content)
146
+ end
147
+
148
+ it 'retries and succeeds' do
149
+ expect { render_pact(retry_limit: 0) }.to raise_error(PactFile::HttpError, /status=500/)
150
+ end
151
+ end
152
+
153
+ context 'with retry_limit option and open timeout error' do
154
+ before do
155
+ stub_request(:get, uri_without_userinfo).to_raise(Net::OpenTimeout).
156
+ then.to_return(status: 200, body: pact_content)
157
+ end
158
+
159
+ it 'retries and succeeds' do
160
+ expect { render_pact(retry_limit: 0) }.to raise_error(Net::OpenTimeout)
161
+ end
162
+ end
163
+
164
+ context 'with retry_limit option which is greater than default retry limit' do
165
+ before do
166
+ stub_request(:get, uri_without_userinfo).to_return(status: 500).
167
+ then.to_return(status: 500).
168
+ then.to_return(status: 500).
169
+ then.to_return(status: 500).
170
+ then.to_return(status: 200, body: pact_content)
171
+ end
172
+
173
+ it 'retries and succeeds' do
174
+ expect(render_pact(retry_limit: 4)).to eq(pact_content)
175
+ end
176
+ end
177
+ end
45
178
  end
46
179
  end
47
- end
180
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact-support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Fraser
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2016-04-29 00:00:00.000000000 Z
15
+ date: 2016-05-03 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: randexp
@@ -146,14 +146,14 @@ dependencies:
146
146
  requirements:
147
147
  - - "~>"
148
148
  - !ruby/object:Gem::Version
149
- version: 1.18.0
149
+ version: 2.0.0
150
150
  type: :development
151
151
  prerelease: false
152
152
  version_requirements: !ruby/object:Gem::Requirement
153
153
  requirements:
154
154
  - - "~>"
155
155
  - !ruby/object:Gem::Version
156
- version: 1.18.0
156
+ version: 2.0.0
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: pry
159
159
  requirement: !ruby/object:Gem::Requirement