jira-ruby 2.3.0 → 3.0.0.beta2

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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/dependabot.yml +6 -0
  5. data/.github/workflows/CI.yml +29 -0
  6. data/.github/workflows/codeql.yml +96 -0
  7. data/.github/workflows/rubocop.yml +18 -0
  8. data/.gitignore +3 -1
  9. data/.rubocop.yml +120 -0
  10. data/.yardopts +4 -0
  11. data/Gemfile +11 -3
  12. data/Guardfile +2 -0
  13. data/README.md +94 -18
  14. data/Rakefile +3 -4
  15. data/jira-ruby.gemspec +11 -17
  16. data/lib/jira/base.rb +37 -36
  17. data/lib/jira/base_factory.rb +4 -1
  18. data/lib/jira/client.rb +123 -50
  19. data/lib/jira/has_many_proxy.rb +32 -28
  20. data/lib/jira/http_client.rb +80 -13
  21. data/lib/jira/http_error.rb +4 -0
  22. data/lib/jira/jwt_client.rb +18 -42
  23. data/lib/jira/oauth_client.rb +68 -3
  24. data/lib/jira/railtie.rb +2 -0
  25. data/lib/jira/request_client.rb +31 -2
  26. data/lib/jira/resource/agile.rb +7 -9
  27. data/lib/jira/resource/applinks.rb +5 -3
  28. data/lib/jira/resource/attachment.rb +128 -3
  29. data/lib/jira/resource/board.rb +5 -3
  30. data/lib/jira/resource/board_configuration.rb +2 -0
  31. data/lib/jira/resource/comment.rb +2 -0
  32. data/lib/jira/resource/component.rb +2 -0
  33. data/lib/jira/resource/createmeta.rb +3 -1
  34. data/lib/jira/resource/field.rb +13 -12
  35. data/lib/jira/resource/filter.rb +2 -0
  36. data/lib/jira/resource/issue.rb +95 -44
  37. data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
  38. data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
  39. data/lib/jira/resource/issuelink.rb +6 -3
  40. data/lib/jira/resource/issuelinktype.rb +2 -0
  41. data/lib/jira/resource/issuetype.rb +2 -0
  42. data/lib/jira/resource/priority.rb +2 -0
  43. data/lib/jira/resource/project.rb +4 -2
  44. data/lib/jira/resource/rapidview.rb +5 -3
  45. data/lib/jira/resource/remotelink.rb +2 -0
  46. data/lib/jira/resource/resolution.rb +2 -0
  47. data/lib/jira/resource/serverinfo.rb +2 -0
  48. data/lib/jira/resource/sprint.rb +14 -23
  49. data/lib/jira/resource/status.rb +7 -1
  50. data/lib/jira/resource/status_category.rb +10 -0
  51. data/lib/jira/resource/suggested_issue.rb +2 -0
  52. data/lib/jira/resource/transition.rb +2 -0
  53. data/lib/jira/resource/user.rb +3 -1
  54. data/lib/jira/resource/version.rb +2 -0
  55. data/lib/jira/resource/watcher.rb +3 -2
  56. data/lib/jira/resource/webhook.rb +9 -3
  57. data/lib/jira/resource/worklog.rb +3 -2
  58. data/lib/jira/version.rb +3 -1
  59. data/lib/jira-ruby.rb +5 -3
  60. data/lib/tasks/generate.rake +3 -1
  61. data/spec/data/files/short.txt +1 -0
  62. data/spec/integration/attachment_spec.rb +3 -3
  63. data/spec/integration/comment_spec.rb +8 -8
  64. data/spec/integration/component_spec.rb +7 -7
  65. data/spec/integration/field_spec.rb +3 -3
  66. data/spec/integration/issue_spec.rb +20 -16
  67. data/spec/integration/issuelinktype_spec.rb +3 -3
  68. data/spec/integration/issuetype_spec.rb +3 -3
  69. data/spec/integration/priority_spec.rb +3 -3
  70. data/spec/integration/project_spec.rb +8 -8
  71. data/spec/integration/rapidview_spec.rb +10 -10
  72. data/spec/integration/resolution_spec.rb +3 -3
  73. data/spec/integration/status_category_spec.rb +20 -0
  74. data/spec/integration/status_spec.rb +4 -8
  75. data/spec/integration/transition_spec.rb +2 -2
  76. data/spec/integration/user_spec.rb +34 -11
  77. data/spec/integration/version_spec.rb +7 -7
  78. data/spec/integration/watcher_spec.rb +21 -18
  79. data/spec/integration/webhook_spec.rb +33 -0
  80. data/spec/integration/worklog_spec.rb +8 -8
  81. data/spec/jira/base_factory_spec.rb +13 -3
  82. data/spec/jira/base_spec.rb +135 -98
  83. data/spec/jira/client_spec.rb +63 -47
  84. data/spec/jira/has_many_proxy_spec.rb +3 -3
  85. data/spec/jira/http_client_spec.rb +94 -27
  86. data/spec/jira/http_error_spec.rb +2 -2
  87. data/spec/jira/oauth_client_spec.rb +14 -8
  88. data/spec/jira/request_client_spec.rb +4 -4
  89. data/spec/jira/resource/agile_spec.rb +30 -30
  90. data/spec/jira/resource/attachment_spec.rb +170 -57
  91. data/spec/jira/resource/board_spec.rb +24 -23
  92. data/spec/jira/resource/createmeta_spec.rb +48 -48
  93. data/spec/jira/resource/field_spec.rb +44 -27
  94. data/spec/jira/resource/filter_spec.rb +4 -4
  95. data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
  96. data/spec/jira/resource/issue_spec.rb +49 -43
  97. data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
  98. data/spec/jira/resource/project_factory_spec.rb +3 -2
  99. data/spec/jira/resource/project_spec.rb +14 -14
  100. data/spec/jira/resource/sprint_spec.rb +88 -9
  101. data/spec/jira/resource/status_spec.rb +21 -0
  102. data/spec/jira/resource/user_factory_spec.rb +5 -5
  103. data/spec/jira/resource/worklog_spec.rb +4 -4
  104. data/spec/mock_responses/sprint/1.json +13 -0
  105. data/spec/mock_responses/status/1.json +8 -1
  106. data/spec/mock_responses/status.json +40 -5
  107. data/spec/mock_responses/statuscategory/1.json +7 -0
  108. data/spec/mock_responses/statuscategory.json +30 -0
  109. data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
  110. data/spec/spec_helper.rb +1 -0
  111. data/spec/support/clients_helper.rb +3 -5
  112. data/spec/support/mock_client.rb +9 -0
  113. data/spec/support/mock_response.rb +8 -0
  114. data/spec/support/shared_examples/integration.rb +25 -28
  115. metadata +27 -260
  116. data/.travis.yml +0 -9
  117. data/example.rb +0 -232
  118. data/http-basic-example.rb +0 -113
  119. data/lib/jira/resource/sprint_report.rb +0 -8
  120. data/lib/jira/tasks.rb +0 -0
  121. data/spec/integration/webhook.rb +0 -25
  122. data/spec/jira/jwt_uri_builder_spec.rb +0 -59
@@ -28,7 +28,7 @@ RSpec.shared_examples 'Client Common Tests' do
28
28
  expect(subject).to receive(:merge_default_headers).exactly(3).times.with({})
29
29
 
30
30
  # response for merging headers for http methods with body
31
- expect(subject).to receive(:merge_default_headers).exactly(2).times.with(content_type_header)
31
+ expect(subject).to receive(:merge_default_headers).twice.with(content_type_header)
32
32
 
33
33
  %i[delete get head].each { |method| subject.send(method, '/path', {}) }
34
34
  %i[post put].each { |method| subject.send(method, '/path', '', content_type_header) }
@@ -62,13 +62,22 @@ RSpec.shared_examples 'Client Common Tests' do
62
62
 
63
63
  describe 'SSL client options' do
64
64
  context 'without certificate and key' do
65
- let(:options) { { use_client_cert: true } }
66
- subject { JIRA::Client.new(options) }
65
+ let(:basic_options) { { use_client_cert: true } }
67
66
 
68
- it 'raises an ArgumentError' do
69
- expect { subject }.to raise_exception(ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true')
70
- options[:ssl_client_cert] = '<cert></cert>'
71
- expect { subject }.to raise_exception(ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true')
67
+ it 'raises an ArgumentError when cert is missing' do
68
+ expect do
69
+ JIRA::Client.new(basic_options)
70
+ end.to raise_exception(ArgumentError,
71
+ 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true')
72
+ end
73
+
74
+ it 'raises an ArgumentError when key is missing' do
75
+ options_with_cert = basic_options.merge(ssl_client_cert: '<cert></cert>')
76
+
77
+ expect do
78
+ JIRA::Client.new(options_with_cert)
79
+ end.to raise_exception(ArgumentError,
80
+ 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true')
72
81
  end
73
82
  end
74
83
  end
@@ -77,11 +86,13 @@ end
77
86
  RSpec.shared_examples 'HttpClient tests' do
78
87
  it 'makes a valid request' do
79
88
  %i[delete get head].each do |method|
80
- expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
89
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', nil,
90
+ headers).and_return(successful_response)
81
91
  subject.send(method, '/path', headers)
82
92
  end
83
93
  %i[post put].each do |method|
84
- expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
94
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', '',
95
+ merged_headers).and_return(successful_response)
85
96
  subject.send(method, '/path', '', headers)
86
97
  end
87
98
  end
@@ -96,21 +107,23 @@ RSpec.shared_examples 'OAuth Common Tests' do
96
107
  token = double
97
108
  expect(OAuth::AccessToken).to receive(:new).with(subject.consumer, '', '').and_return(token)
98
109
 
99
- expect(subject.authenticated?).to be_falsey
110
+ expect(subject).not_to be_authenticated
100
111
  access_token = subject.set_access_token('', '')
101
112
  expect(access_token).to eq(token)
102
113
  expect(subject.access_token).to eq(token)
103
- expect(subject.authenticated?).to be_truthy
114
+ expect(subject).to be_authenticated
104
115
  end
105
116
 
106
117
  describe 'that call a oauth client' do
107
118
  specify 'which makes a request' do
108
119
  %i[delete get head].each do |method|
109
- expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
120
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', nil,
121
+ headers).and_return(successful_response)
110
122
  subject.send(method, '/path', {})
111
123
  end
112
124
  %i[post put].each do |method|
113
- expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
125
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', '',
126
+ merged_headers).and_return(successful_response)
114
127
  subject.send(method, '/path', '', {})
115
128
  end
116
129
  end
@@ -128,22 +141,24 @@ describe JIRA::Client do
128
141
  let(:headers) { { 'Accept' => 'application/json' } }
129
142
  let(:merged_headers) { headers.merge(content_type_header) }
130
143
 
131
- context 'behaviour that applies to all client classes irrespective of authentication method' do
144
+ context 'without regard to the authentication method, this behaviour applies to all client classes' do
132
145
  it 'allows the overriding of some options' do
133
- client = JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar', site: 'http://foo.com/')
146
+ client = described_class.new(consumer_key: 'foo', consumer_secret: 'bar', site: 'http://foo.com/')
134
147
  expect(client.options[:site]).to eq('http://foo.com/')
135
148
  expect(JIRA::Client::DEFAULT_OPTIONS[:site]).not_to eq('http://foo.com/')
136
149
  end
137
150
  end
138
151
 
139
152
  context 'with basic http authentication' do
140
- subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :basic) }
153
+ subject { described_class.new(username: 'foo', password: 'bar', auth_type: :basic) }
141
154
 
142
- before(:each) do
143
- stub_request(:get, 'https://foo:bar@localhost:2990/jira/rest/api/2/project')
155
+ before do
156
+ stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
157
+ .with(headers: { 'Authorization' => "Basic #{Base64.strict_encode64('foo:bar').chomp}" })
144
158
  .to_return(status: 200, body: '[]', headers: {})
145
159
 
146
- stub_request(:get, 'https://foo:badpassword@localhost:2990/jira/rest/api/2/project')
160
+ stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
161
+ .with(headers: { 'Authorization' => "Basic #{Base64.strict_encode64('foo:badpassword').chomp}" })
147
162
  .to_return(status: 401, headers: {})
148
163
  end
149
164
 
@@ -157,33 +172,33 @@ describe JIRA::Client do
157
172
  expect(subject.options[:password]).to eq('bar')
158
173
  end
159
174
 
160
- it 'fails with wrong user name and password' do
161
- bad_login = JIRA::Client.new(username: 'foo', password: 'badpassword', auth_type: :basic)
162
- expect(bad_login.authenticated?).to be_falsey
163
- expect { bad_login.Project.all }.to raise_error JIRA::HTTPError
164
- end
165
-
166
175
  it 'only returns a true for #authenticated? once we have requested some data' do
167
- expect(subject.authenticated?).to be_falsey
176
+ expect(subject.authenticated?).to be_nil
168
177
  expect(subject.Project.all).to be_empty
169
- expect(subject.authenticated?).to be_truthy
178
+ expect(subject).to be_authenticated
179
+ end
180
+
181
+ it 'fails with wrong user name and password' do
182
+ bad_login = described_class.new(username: 'foo', password: 'badpassword', auth_type: :basic)
183
+ expect(bad_login).not_to be_authenticated
184
+ expect { bad_login.Project.all }.to raise_error JIRA::HTTPError
170
185
  end
171
186
  end
172
187
 
173
188
  context 'with cookie authentication' do
174
- subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :cookie) }
189
+ subject { described_class.new(username: 'foo', password: 'bar', auth_type: :cookie) }
175
190
 
176
191
  let(:session_cookie) { '6E3487971234567896704A9EB4AE501F' }
177
192
  let(:session_body) do
178
193
  {
179
- 'session': { 'name' => 'JSESSIONID', 'value' => session_cookie },
180
- 'loginInfo': { 'failedLoginCount' => 1, 'loginCount' => 2,
181
- 'lastFailedLoginTime' => (DateTime.now - 2).iso8601,
182
- 'previousLoginTime' => (DateTime.now - 5).iso8601 }
194
+ session: { 'name' => 'JSESSIONID', 'value' => session_cookie },
195
+ loginInfo: { 'failedLoginCount' => 1, 'loginCount' => 2,
196
+ 'lastFailedLoginTime' => (DateTime.now - 2).iso8601,
197
+ 'previousLoginTime' => (DateTime.now - 5).iso8601 }
183
198
  }
184
199
  end
185
200
 
186
- before(:each) do
201
+ before do
187
202
  # General case of API call with no authentication, or wrong authentication
188
203
  stub_request(:post, 'https://localhost:2990/jira/rest/auth/1/session')
189
204
  .to_return(status: 401, headers: {})
@@ -210,7 +225,7 @@ describe JIRA::Client do
210
225
  end
211
226
 
212
227
  it 'does not authenticate with an incorrect username and password' do
213
- bad_client = JIRA::Client.new(username: 'foo', password: 'bad_password', auth_type: :cookie)
228
+ bad_client = described_class.new(username: 'foo', password: 'bad_password', auth_type: :cookie)
214
229
  expect(bad_client).not_to be_authenticated
215
230
  end
216
231
 
@@ -222,7 +237,7 @@ describe JIRA::Client do
222
237
 
223
238
  context 'with jwt authentication' do
224
239
  subject do
225
- JIRA::Client.new(
240
+ described_class.new(
226
241
  issuer: 'foo',
227
242
  base_url: 'https://host.tld',
228
243
  shared_secret: 'shared_secret_key',
@@ -230,10 +245,10 @@ describe JIRA::Client do
230
245
  )
231
246
  end
232
247
 
233
- before(:each) do
248
+ before do
234
249
  stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
235
- .with(query: hash_including(:jwt))
236
- .to_return(status: 200, body: '[]', headers: {})
250
+ .with(headers: { 'Authorization' => /JWT .+/ })
251
+ .to_return(status: 200, body: '[]', headers: {})
237
252
  end
238
253
 
239
254
  include_examples 'Client Common Tests'
@@ -248,12 +263,12 @@ describe JIRA::Client do
248
263
  context 'with a incorrect jwt key' do
249
264
  before do
250
265
  stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
251
- .with(query: hash_including(:jwt))
252
- .to_return(status: 401, body: '[]', headers: {})
266
+ .with(headers: { 'Authorization' => /JWT .+/ })
267
+ .to_return(status: 401, body: '[]', headers: {})
253
268
  end
254
269
 
255
270
  it 'is not authenticated' do
256
- expect(subject.authenticated?).to be_falsey
271
+ expect(subject).not_to be_authenticated
257
272
  end
258
273
 
259
274
  it 'raises a JIRA::HTTPError when trying to fetch projects' do
@@ -262,27 +277,28 @@ describe JIRA::Client do
262
277
  end
263
278
 
264
279
  it 'only returns a true for #authenticated? once we have requested some data' do
265
- expect(subject.authenticated?).to be_falsey
280
+ expect(subject).not_to be_authenticated
266
281
  expect(subject.Project.all).to be_empty
267
- expect(subject.authenticated?).to be_truthy
282
+ expect(subject).to be_authenticated
268
283
  end
269
284
  end
270
285
 
271
- context 'oauth authentication' do
272
- subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar') }
286
+ context 'with oauth' do
287
+ subject { described_class.new(consumer_key: 'foo', consumer_secret: 'bar') }
273
288
 
274
289
  include_examples 'OAuth Common Tests'
275
290
  end
276
291
 
277
292
  context 'with oauth_2legged' do
278
- subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged) }
293
+ subject { described_class.new(consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged) }
279
294
 
280
295
  include_examples 'OAuth Common Tests'
281
296
  end
282
297
 
283
298
  context 'with unknown options' do
299
+ subject { described_class.new(options) }
300
+
284
301
  let(:options) { { 'username' => 'foo', 'password' => 'bar', auth_type: :basic } }
285
- subject { JIRA::Client.new(options) }
286
302
 
287
303
  it 'raises an ArgumentError' do
288
304
  expect { subject }.to raise_exception(ArgumentError, 'Unknown option(s) given: ["username", "password"]')
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe JIRA::HasManyProxy do
4
4
  class Foo; end
5
5
 
6
- subject { JIRA::HasManyProxy.new(parent, Foo, collection) }
6
+ subject { described_class.new(parent, Foo, collection) }
7
7
 
8
8
  let(:parent) { double('parent') }
9
9
  let(:collection) { double('collection') }
@@ -25,7 +25,7 @@ describe JIRA::HasManyProxy do
25
25
  foo = double('foo')
26
26
  allow(parent).to receive(:client).and_return(client)
27
27
  allow(parent).to receive(:to_sym).and_return(:parent)
28
- expect(Foo).to receive(:new).with(client, attrs: { 'foo' => 'bar' }, parent: parent).and_return(foo)
28
+ expect(Foo).to receive(:new).with(client, attrs: { 'foo' => 'bar' }, parent:).and_return(foo)
29
29
  expect(collection).to receive(:<<).with(foo)
30
30
  expect(subject.build('foo' => 'bar')).to eq(foo)
31
31
  end
@@ -35,7 +35,7 @@ describe JIRA::HasManyProxy do
35
35
  client = double('client')
36
36
  allow(parent).to receive(:client).and_return(client)
37
37
  allow(parent).to receive(:to_sym).and_return(:parent)
38
- expect(Foo).to receive(:all).with(client, parent: parent).and_return(foo)
38
+ expect(Foo).to receive(:all).with(client, parent:).and_return(foo)
39
39
  expect(subject.all).to eq(foo)
40
40
  end
41
41
 
@@ -5,7 +5,7 @@ describe JIRA::HttpClient do
5
5
  options = JIRA::Client::DEFAULT_OPTIONS
6
6
  .merge(JIRA::HttpClient::DEFAULT_OPTIONS)
7
7
  .merge(basic_auth_credentials)
8
- JIRA::HttpClient.new(options)
8
+ described_class.new(options)
9
9
  end
10
10
 
11
11
  let(:basic_cookie_client) do
@@ -13,12 +13,12 @@ describe JIRA::HttpClient do
13
13
  .merge(JIRA::HttpClient::DEFAULT_OPTIONS)
14
14
  .merge(use_cookies: true)
15
15
  .merge(basic_auth_credentials)
16
- JIRA::HttpClient.new(options)
16
+ described_class.new(options)
17
17
  end
18
18
 
19
19
  let(:custom_ssl_version_client) do
20
20
  options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(ssl_version: :TLSv1_2)
21
- JIRA::HttpClient.new(options)
21
+ described_class.new(options)
22
22
  end
23
23
 
24
24
  let(:basic_cookie_client_with_context_path) do
@@ -26,7 +26,7 @@ describe JIRA::HttpClient do
26
26
  use_cookies: true,
27
27
  context_path: '/context'
28
28
  )
29
- JIRA::HttpClient.new(options)
29
+ described_class.new(options)
30
30
  end
31
31
 
32
32
  let(:basic_cookie_client_with_additional_cookies) do
@@ -37,7 +37,7 @@ describe JIRA::HttpClient do
37
37
  additional_cookies: ['sessionToken=abc123', 'internal=true']
38
38
  )
39
39
  .merge(basic_auth_credentials)
40
- JIRA::HttpClient.new(options)
40
+ described_class.new(options)
41
41
  end
42
42
 
43
43
  let(:basic_client_cert_client) do
@@ -46,13 +46,13 @@ describe JIRA::HttpClient do
46
46
  cert: 'public certificate contents',
47
47
  key: 'private key contents'
48
48
  )
49
- JIRA::HttpClient.new(options)
49
+ described_class.new(options)
50
50
  end
51
51
 
52
52
  let(:basic_client_with_no_auth_credentials) do
53
53
  options = JIRA::Client::DEFAULT_OPTIONS
54
54
  .merge(JIRA::HttpClient::DEFAULT_OPTIONS)
55
- JIRA::HttpClient.new(options)
55
+ described_class.new(options)
56
56
  end
57
57
 
58
58
  let(:basic_auth_credentials) do
@@ -66,7 +66,14 @@ describe JIRA::HttpClient do
66
66
  proxy_username: 'proxyUsername',
67
67
  proxy_password: 'proxyPassword'
68
68
  )
69
- JIRA::HttpClient.new(options)
69
+ described_class.new(options)
70
+ end
71
+
72
+ let(:basic_client_with_max_retries) do
73
+ options = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(
74
+ max_retries: 2
75
+ )
76
+ described_class.new(options)
70
77
  end
71
78
 
72
79
  let(:response) do
@@ -81,6 +88,35 @@ describe JIRA::HttpClient do
81
88
  response
82
89
  end
83
90
 
91
+ context 'with a simple client' do
92
+ let(:client) do
93
+ options_local = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(
94
+ proxy_address: 'proxyAddress',
95
+ proxy_port: 42,
96
+ proxy_username: 'proxyUsername',
97
+ proxy_password: 'proxyPassword'
98
+ )
99
+ described_class.new(options_local)
100
+ end
101
+
102
+ describe 'HttpClient#basic_auth_http_conn' do
103
+ subject(:http_conn) { basic_client.basic_auth_http_conn }
104
+
105
+ it 'creates an instance of Net:HTTP for a basic auth client' do
106
+ expect(http_conn.class).to eq(Net::HTTP)
107
+ end
108
+
109
+ it 'the connection created has no proxy' do
110
+ http_conn
111
+
112
+ expect(http_conn.proxy_address).to be_nil
113
+ expect(http_conn.proxy_port).to be_nil
114
+ expect(http_conn.proxy_user).to be_nil
115
+ expect(http_conn.proxy_pass).to be_nil
116
+ end
117
+ end
118
+ end
119
+
84
120
  it 'creates an instance of Net:HTTP for a basic auth client' do
85
121
  expect(basic_client.basic_auth_http_conn.class).to eq(Net::HTTP)
86
122
  end
@@ -111,7 +147,8 @@ describe JIRA::HttpClient do
111
147
  basic_auth_http_conn = double
112
148
  request = double
113
149
  allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
114
- expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).exactly(5).times.and_return(request)
150
+ expect(request).to receive(:basic_auth).with(basic_client.options[:username],
151
+ basic_client.options[:password]).exactly(5).times.and_return(request)
115
152
  expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(response)
116
153
  %i[delete get head].each do |method|
117
154
  expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request)
@@ -130,7 +167,8 @@ describe JIRA::HttpClient do
130
167
  basic_auth_http_conn = double
131
168
  request = double
132
169
  allow(basic_cookie_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
133
- expect(request).to receive(:basic_auth).with(basic_cookie_client.options[:username], basic_cookie_client.options[:password]).exactly(5).times.and_return(request)
170
+ expect(request).to receive(:basic_auth).with(basic_cookie_client.options[:username],
171
+ basic_cookie_client.options[:password]).exactly(5).times.and_return(request)
134
172
  expect(cookie_response).to receive(:get_fields).with('set-cookie').exactly(5).times
135
173
  expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(cookie_response)
136
174
  %i[delete get head].each do |method|
@@ -151,7 +189,8 @@ describe JIRA::HttpClient do
151
189
  basic_auth_http_conn = double
152
190
  request = double
153
191
  allow(client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
154
- expect(request).to receive(:basic_auth).with(client.options[:username], client.options[:password]).exactly(5).times.and_return(request)
192
+ expect(request).to receive(:basic_auth).with(client.options[:username],
193
+ client.options[:password]).exactly(5).times.and_return(request)
155
194
  expect(request).to receive(:add_field).with('Cookie', 'sessionToken=abc123; internal=true').exactly(5).times
156
195
  expect(cookie_response).to receive(:get_fields).with('set-cookie').exactly(5).times
157
196
  expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(cookie_response)
@@ -174,7 +213,8 @@ describe JIRA::HttpClient do
174
213
  expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request)
175
214
 
176
215
  expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response)
177
- expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request)
216
+ expect(http_request).to receive(:basic_auth).with(basic_client.options[:username],
217
+ basic_client.options[:password]).and_return(http_request)
178
218
  allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
179
219
  basic_client.make_request(:get, '/foo', body, headers)
180
220
  end
@@ -187,7 +227,8 @@ describe JIRA::HttpClient do
187
227
  expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request)
188
228
 
189
229
  expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response)
190
- expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request)
230
+ expect(http_request).to receive(:basic_auth).with(basic_client.options[:username],
231
+ basic_client.options[:password]).and_return(http_request)
191
232
  allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
192
233
  basic_client.make_request(:get, 'http://mydomain.com/foo', body, headers)
193
234
  end
@@ -254,19 +295,29 @@ describe JIRA::HttpClient do
254
295
  expect(proxy_configuration.proxy_pass).to be_nil
255
296
  end
256
297
 
257
- it 'sets up a proxied http connection when using proxy options' do
258
- uri = double
259
- host = double
260
- port = double
298
+ context 'when the client has proxy settings' do
299
+ subject(:proxy_conn) { proxy_client.basic_auth_http_conn }
300
+
301
+ let(:proxy_client) do
302
+ options_local = JIRA::Client::DEFAULT_OPTIONS.merge(JIRA::HttpClient::DEFAULT_OPTIONS).merge(
303
+ proxy_address: 'proxyAddress',
304
+ proxy_port: 42,
305
+ proxy_username: 'proxyUsername',
306
+ proxy_password: 'proxyPassword'
307
+ )
308
+ described_class.new(options_local)
309
+ end
261
310
 
262
- expect(uri).to receive(:host).and_return(host)
263
- expect(uri).to receive(:port).and_return(port)
311
+ describe 'HttpClient#basic_auth_http_conn' do
312
+ it 'creates a Net:HTTP instance for a basic auth client setting up a proxied http connection' do
313
+ expect(proxy_conn.class).to eq(Net::HTTP)
264
314
 
265
- proxy_configuration = proxy_client.http_conn(uri).class
266
- expect(proxy_configuration.proxy_address).to eq(proxy_client.options[:proxy_address])
267
- expect(proxy_configuration.proxy_port).to eq(proxy_client.options[:proxy_port])
268
- expect(proxy_configuration.proxy_user).to eq(proxy_client.options[:proxy_username])
269
- expect(proxy_configuration.proxy_pass).to eq(proxy_client.options[:proxy_password])
315
+ expect(proxy_conn.proxy_address).to eq(proxy_client.options[:proxy_address])
316
+ expect(proxy_conn.proxy_port).to eq(proxy_client.options[:proxy_port])
317
+ expect(proxy_conn.proxy_user).to eq(proxy_client.options[:proxy_username])
318
+ expect(proxy_conn.proxy_pass).to eq(proxy_client.options[:proxy_password])
319
+ end
320
+ end
270
321
  end
271
322
 
272
323
  it 'can use client certificates' do
@@ -286,10 +337,25 @@ describe JIRA::HttpClient do
286
337
  end
287
338
 
288
339
  it 'can use a certificate authority file' do
289
- client = JIRA::HttpClient.new(JIRA::Client::DEFAULT_OPTIONS.merge(ca_file: '/opt/custom.ca.pem'))
340
+ client = described_class.new(JIRA::Client::DEFAULT_OPTIONS.merge(ca_file: '/opt/custom.ca.pem'))
290
341
  expect(client.http_conn(client.uri).ca_file).to eql('/opt/custom.ca.pem')
291
342
  end
292
343
 
344
+ it 'allows overriding max_retries' do
345
+ http_conn = double
346
+ uri = double
347
+ host = double
348
+ port = double
349
+ expect(uri).to receive(:host).and_return(host)
350
+ expect(uri).to receive(:port).and_return(port)
351
+ expect(Net::HTTP).to receive(:new).with(host, port).and_return(http_conn)
352
+ expect(http_conn).to receive(:use_ssl=).with(basic_client.options[:use_ssl]).and_return(http_conn)
353
+ expect(http_conn).to receive(:verify_mode=).with(basic_client.options[:ssl_verify_mode]).and_return(http_conn)
354
+ expect(http_conn).to receive(:read_timeout=).with(basic_client.options[:read_timeout]).and_return(http_conn)
355
+ expect(http_conn).to receive(:max_retries=).with(basic_client_with_max_retries.options[:max_retries]).and_return(http_conn)
356
+ expect(basic_client_with_max_retries.http_conn(uri)).to eq(http_conn)
357
+ end
358
+
293
359
  it 'returns a http connection' do
294
360
  http_conn = double
295
361
  uri = double
@@ -307,7 +373,7 @@ describe JIRA::HttpClient do
307
373
  let(:data) { {} }
308
374
  let(:headers) { { 'X-Atlassian-Token' => 'no-check' } }
309
375
  let(:basic_auth_http_conn) { double }
310
- let(:request) { double('Http Request', path: path) }
376
+ let(:request) { double('Http Request', path:) }
311
377
  let(:response) { double('response') }
312
378
 
313
379
  before do
@@ -318,7 +384,8 @@ describe JIRA::HttpClient do
318
384
  end
319
385
 
320
386
  it 'performs a basic http client request' do
321
- expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(request)
387
+ expect(request).to receive(:basic_auth).with(basic_client.options[:username],
388
+ basic_client.options[:password]).and_return(request)
322
389
 
323
390
  subject
324
391
  end
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::HTTPError do
4
+ subject { described_class.new(response) }
5
+
4
6
  let(:response) do
5
7
  response = double('response')
6
8
  allow(response).to receive(:code).and_return(401)
@@ -8,8 +10,6 @@ describe JIRA::HTTPError do
8
10
  response
9
11
  end
10
12
 
11
- subject { described_class.new(response) }
12
-
13
13
  it 'takes the response object as an argument' do
14
14
  expect(subject.response).to eq(response)
15
15
  end
@@ -4,7 +4,7 @@ describe JIRA::OauthClient do
4
4
  let(:oauth_client) do
5
5
  options = { consumer_key: 'foo', consumer_secret: 'bar' }
6
6
  options = JIRA::Client::DEFAULT_OPTIONS.merge(options)
7
- JIRA::OauthClient.new(options)
7
+ described_class.new(options)
8
8
  end
9
9
 
10
10
  let(:response) do
@@ -37,7 +37,7 @@ describe JIRA::OauthClient do
37
37
 
38
38
  it 'could pre-process the response body in a block' do
39
39
  response = Net::HTTPSuccess.new(1.0, '200', 'OK')
40
- allow_any_instance_of(OAuth::Consumer).to receive(:request).and_return(response)
40
+ allow(oauth_client.consumer).to receive(:request).and_return(response)
41
41
  allow(response).to receive(:body).and_return('&oauth_token=token&oauth_token_secret=secret&password=top_secret')
42
42
 
43
43
  result = oauth_client.request_token do |response_body|
@@ -124,19 +124,23 @@ describe JIRA::OauthClient do
124
124
  it 'performs a request' do
125
125
  expect(access_token).to receive(:send).with(:get, '/foo', headers).and_return(response)
126
126
 
127
-
128
127
  oauth_client.request(:get, '/foo', body, headers)
129
128
  end
130
129
 
131
- context 'for a multipart request' do
130
+ context 'when a multipart request' do
132
131
  subject { oauth_client.make_multipart_request('/path', data, headers) }
133
132
 
134
133
  let(:data) { {} }
135
134
  let(:headers) { {} }
136
135
 
137
136
  it 'signs the access_token and performs the request' do
137
+ http_mock = double('HTTP')
138
+
139
+ consumer_mock = oauth_client.consumer
140
+
138
141
  expect(access_token).to receive(:sign!).with(an_instance_of(Net::HTTP::Post::Multipart))
139
- expect(oauth_client.consumer).to receive_message_chain(:http, :request).with(an_instance_of(Net::HTTP::Post::Multipart))
142
+ expect(consumer_mock).to receive(:http).and_return(http_mock)
143
+ expect(http_mock).to receive(:request).with(an_instance_of(Net::HTTP::Post::Multipart))
140
144
 
141
145
  subject
142
146
  end
@@ -147,7 +151,7 @@ describe JIRA::OauthClient do
147
151
  let(:oauth__2legged_client) do
148
152
  options = { consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged }
149
153
  options = JIRA::Client::DEFAULT_OPTIONS.merge(options)
150
- JIRA::OauthClient.new(options)
154
+ described_class.new(options)
151
155
  end
152
156
 
153
157
  it 'responds to the http methods adding oauth_token parameter' do
@@ -169,11 +173,13 @@ describe JIRA::OauthClient do
169
173
  mock_access_token = double
170
174
  allow(oauth__2legged_client).to receive(:access_token).and_return(mock_access_token)
171
175
  %i[delete get head].each do |method|
172
- expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=', headers).and_return(response)
176
+ expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=',
177
+ headers).and_return(response)
173
178
  oauth__2legged_client.make_request(method, '/path?any_param=toto', '', headers)
174
179
  end
175
180
  %i[post put].each do |method|
176
- expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=', '', headers).and_return(response)
181
+ expect(mock_access_token).to receive(method).with('/path?any_param=toto&oauth_token=', '',
182
+ headers).and_return(response)
177
183
  oauth__2legged_client.make_request(method, '/path?any_param=toto', '', headers)
178
184
  end
179
185
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::RequestClient do
4
- let(:request_client) { JIRA::RequestClient.new }
4
+ let(:request_client) { described_class.new }
5
5
 
6
6
  describe '#request' do
7
7
  subject(:request) { request_client.request(:get, '/foo', '', {}) }
@@ -15,7 +15,7 @@ describe JIRA::RequestClient do
15
15
  end
16
16
 
17
17
  it 'raises an exception' do
18
- expect{ subject }.to raise_exception(JIRA::HTTPError)
18
+ expect { subject }.to raise_exception(JIRA::HTTPError)
19
19
  end
20
20
  end
21
21
  end
@@ -34,8 +34,8 @@ describe JIRA::RequestClient do
34
34
  end
35
35
 
36
36
  it 'raises an exception' do
37
- expect{ subject }.to raise_exception(JIRA::HTTPError)
37
+ expect { subject }.to raise_exception(JIRA::HTTPError)
38
38
  end
39
39
  end
40
40
  end
41
- end
41
+ end