jira-ruby 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +7 -1
- data/Guardfile +1 -1
- data/Rakefile +4 -5
- data/http-basic-example.rb +13 -12
- data/jira-ruby.gemspec +9 -10
- data/lib/jira-ruby.rb +5 -2
- data/lib/jira/base.rb +49 -48
- data/lib/jira/base_factory.rb +1 -4
- data/lib/jira/client.rb +29 -20
- data/lib/jira/has_many_proxy.rb +0 -1
- data/lib/jira/http_client.rb +9 -10
- data/lib/jira/http_error.rb +3 -5
- data/lib/jira/oauth_client.rb +19 -20
- data/lib/jira/request_client.rb +3 -4
- data/lib/jira/resource/agile.rb +10 -8
- data/lib/jira/resource/applinks.rb +5 -8
- data/lib/jira/resource/attachment.rb +1 -2
- data/lib/jira/resource/board.rb +84 -0
- data/lib/jira/resource/comment.rb +0 -2
- data/lib/jira/resource/component.rb +1 -3
- data/lib/jira/resource/createmeta.rb +12 -14
- data/lib/jira/resource/field.rb +22 -22
- data/lib/jira/resource/filter.rb +2 -2
- data/lib/jira/resource/issue.rb +41 -39
- data/lib/jira/resource/issuelink.rb +3 -5
- data/lib/jira/resource/issuelinktype.rb +0 -1
- data/lib/jira/resource/issuetype.rb +1 -3
- data/lib/jira/resource/priority.rb +1 -3
- data/lib/jira/resource/project.rb +5 -7
- data/lib/jira/resource/rapidview.rb +28 -7
- data/lib/jira/resource/remotelink.rb +1 -4
- data/lib/jira/resource/resolution.rb +2 -4
- data/lib/jira/resource/serverinfo.rb +1 -2
- data/lib/jira/resource/sprint.rb +82 -18
- data/lib/jira/resource/sprint_report.rb +8 -0
- data/lib/jira/resource/status.rb +1 -3
- data/lib/jira/resource/transition.rb +2 -6
- data/lib/jira/resource/user.rb +12 -2
- data/lib/jira/resource/version.rb +1 -3
- data/lib/jira/resource/watcher.rb +1 -5
- data/lib/jira/resource/webhook.rb +3 -6
- data/lib/jira/resource/worklog.rb +3 -5
- data/lib/jira/version.rb +1 -1
- data/lib/tasks/generate.rake +4 -4
- data/spec/integration/attachment_spec.rb +15 -16
- data/spec/integration/comment_spec.rb +31 -34
- data/spec/integration/component_spec.rb +21 -24
- data/spec/integration/field_spec.rb +15 -18
- data/spec/integration/issue_spec.rb +44 -48
- data/spec/integration/issuelinktype_spec.rb +8 -11
- data/spec/integration/issuetype_spec.rb +5 -7
- data/spec/integration/priority_spec.rb +5 -8
- data/spec/integration/project_spec.rb +13 -20
- data/spec/integration/rapidview_spec.rb +17 -10
- data/spec/integration/resolution_spec.rb +7 -10
- data/spec/integration/status_spec.rb +5 -8
- data/spec/integration/transition_spec.rb +17 -20
- data/spec/integration/user_spec.rb +24 -8
- data/spec/integration/version_spec.rb +21 -25
- data/spec/integration/watcher_spec.rb +28 -34
- data/spec/integration/webhook.rb +8 -17
- data/spec/integration/worklog_spec.rb +30 -34
- data/spec/jira/base_factory_spec.rb +11 -12
- data/spec/jira/base_spec.rb +204 -228
- data/spec/jira/client_spec.rb +26 -28
- data/spec/jira/has_many_proxy_spec.rb +11 -12
- data/spec/jira/http_client_spec.rb +51 -52
- data/spec/jira/http_error_spec.rb +7 -9
- data/spec/jira/oauth_client_spec.rb +44 -46
- data/spec/jira/request_client_spec.rb +5 -5
- data/spec/jira/resource/agile_spec.rb +5 -7
- data/spec/jira/resource/attachment_spec.rb +25 -26
- data/spec/jira/resource/board_spec.rb +175 -0
- data/spec/jira/resource/createmeta_spec.rb +29 -32
- data/spec/jira/resource/field_spec.rb +42 -48
- data/spec/jira/resource/filter_spec.rb +40 -40
- data/spec/jira/resource/issue_spec.rb +87 -89
- data/spec/jira/resource/issuelink_spec.rb +1 -1
- data/spec/jira/resource/project_factory_spec.rb +2 -4
- data/spec/jira/resource/project_spec.rb +33 -33
- data/spec/jira/resource/sprint_spec.rb +78 -0
- data/spec/jira/resource/user_factory_spec.rb +6 -8
- data/spec/jira/resource/worklog_spec.rb +9 -11
- data/spec/spec_helper.rb +8 -9
- data/spec/support/clients_helper.rb +4 -4
- data/spec/support/shared_examples/integration.rb +60 -77
- metadata +59 -53
@@ -1,45 +1,44 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe JIRA::BaseFactory do
|
4
|
+
class JIRA::Resource::FooFactory < JIRA::BaseFactory; end
|
5
|
+
class JIRA::Resource::Foo; end
|
4
6
|
|
5
|
-
|
6
|
-
class JIRA::Resource::Foo ; end
|
7
|
-
|
8
|
-
let(:client) { double() }
|
7
|
+
let(:client) { double }
|
9
8
|
subject { JIRA::Resource::FooFactory.new(client) }
|
10
9
|
|
11
|
-
it
|
10
|
+
it 'initializes correctly' do
|
12
11
|
expect(subject.class).to eq(JIRA::Resource::FooFactory)
|
13
12
|
expect(subject.client).to eq(client)
|
14
13
|
expect(subject.target_class).to eq(JIRA::Resource::Foo)
|
15
14
|
end
|
16
15
|
|
17
|
-
it
|
16
|
+
it 'proxies all to the target class' do
|
18
17
|
expect(JIRA::Resource::Foo).to receive(:all).with(client)
|
19
18
|
subject.all
|
20
19
|
end
|
21
20
|
|
22
|
-
it
|
21
|
+
it 'proxies find to the target class' do
|
23
22
|
expect(JIRA::Resource::Foo).to receive(:find).with(client, 'FOO')
|
24
23
|
subject.find('FOO')
|
25
24
|
end
|
26
25
|
|
27
|
-
it
|
26
|
+
it 'returns the target class' do
|
28
27
|
expect(subject.target_class).to eq(JIRA::Resource::Foo)
|
29
28
|
end
|
30
29
|
|
31
|
-
it
|
32
|
-
attrs = double
|
30
|
+
it 'proxies build to the target class' do
|
31
|
+
attrs = double
|
33
32
|
expect(JIRA::Resource::Foo).to receive(:build).with(client, attrs)
|
34
33
|
subject.build(attrs)
|
35
34
|
end
|
36
35
|
|
37
|
-
it
|
36
|
+
it 'proxies collection path to the target class' do
|
38
37
|
expect(JIRA::Resource::Foo).to receive(:collection_path).with(client)
|
39
38
|
subject.collection_path
|
40
39
|
end
|
41
40
|
|
42
|
-
it
|
41
|
+
it 'proxies singular path to the target class' do
|
43
42
|
expect(JIRA::Resource::Foo).to receive(:singular_path).with(client, 'FOO')
|
44
43
|
subject.singular_path('FOO')
|
45
44
|
end
|
data/spec/jira/base_spec.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe JIRA::Base do
|
4
|
-
|
5
4
|
class JIRADelegation < SimpleDelegator # :nodoc:
|
6
5
|
end
|
7
6
|
|
@@ -10,57 +9,56 @@ describe JIRA::Base do
|
|
10
9
|
|
11
10
|
class JIRA::Resource::HasOneExample < JIRA::Base # :nodoc:
|
12
11
|
has_one :deadbeef
|
13
|
-
has_one :muffin, :
|
14
|
-
has_one :brunchmuffin, :
|
15
|
-
:
|
12
|
+
has_one :muffin, class: JIRA::Resource::Deadbeef
|
13
|
+
has_one :brunchmuffin, class: JIRA::Resource::Deadbeef,
|
14
|
+
nested_under: 'nested'
|
16
15
|
has_one :breakfastscone,
|
17
|
-
:
|
18
|
-
:
|
16
|
+
class: JIRA::Resource::Deadbeef,
|
17
|
+
nested_under: %w[nested breakfastscone]
|
19
18
|
has_one :irregularly_named_thing,
|
20
|
-
:
|
21
|
-
:
|
19
|
+
class: JIRA::Resource::Deadbeef,
|
20
|
+
attribute_key: 'irregularlyNamedThing'
|
22
21
|
end
|
23
22
|
|
24
23
|
class JIRA::Resource::HasManyExample < JIRA::Base # :nodoc:
|
25
24
|
has_many :deadbeefs
|
26
|
-
has_many :brunchmuffins, :
|
27
|
-
|
25
|
+
has_many :brunchmuffins, class: JIRA::Resource::Deadbeef,
|
26
|
+
nested_under: 'nested'
|
28
27
|
has_many :breakfastscones,
|
29
|
-
:
|
30
|
-
:
|
28
|
+
class: JIRA::Resource::Deadbeef,
|
29
|
+
nested_under: %w[nested breakfastscone]
|
31
30
|
has_many :irregularly_named_things,
|
32
|
-
:
|
33
|
-
:
|
34
|
-
|
31
|
+
class: JIRA::Resource::Deadbeef,
|
32
|
+
attribute_key: 'irregularlyNamedThings'
|
35
33
|
end
|
36
34
|
|
37
|
-
let(:client) { double(
|
38
|
-
let(:attrs) {
|
35
|
+
let(:client) { double('client') }
|
36
|
+
let(:attrs) { {} }
|
39
37
|
|
40
|
-
subject { JIRA::Resource::Deadbeef.new(client, :
|
38
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
|
41
39
|
|
42
40
|
let(:decorated) { JIRADelegation.new(subject) }
|
43
41
|
|
44
|
-
describe
|
45
|
-
describe
|
46
|
-
it
|
42
|
+
describe '#respond_to?' do
|
43
|
+
describe 'when decorated using SimpleDelegator' do
|
44
|
+
it 'responds to client' do
|
47
45
|
expect(decorated.respond_to?(:client)).to eq(true)
|
48
46
|
end
|
49
|
-
it
|
50
|
-
expect
|
47
|
+
it 'does not raise an error' do
|
48
|
+
expect do
|
51
49
|
decorated.respond_to?(:client)
|
52
|
-
|
50
|
+
end.not_to raise_error
|
53
51
|
end
|
54
52
|
end
|
55
53
|
end
|
56
54
|
|
57
|
-
it
|
55
|
+
it 'assigns the client and attrs' do
|
58
56
|
expect(subject.client).to eq(client)
|
59
57
|
expect(subject.attrs).to eq(attrs)
|
60
58
|
end
|
61
59
|
|
62
|
-
it
|
63
|
-
response = double
|
60
|
+
it 'returns all the deadbeefs' do
|
61
|
+
response = double
|
64
62
|
expect(response).to receive(:body).and_return('[{"self":"http://deadbeef/","id":"98765"}]')
|
65
63
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef').and_return(response)
|
66
64
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
@@ -73,8 +71,8 @@ describe JIRA::Base do
|
|
73
71
|
expect(first.expanded?).to be_falsey
|
74
72
|
end
|
75
73
|
|
76
|
-
it
|
77
|
-
response = instance_double(
|
74
|
+
it 'finds a deadbeef by id' do
|
75
|
+
response = instance_double('Response', body: '{"self":"http://deadbeef/","id":"98765"}')
|
78
76
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
|
79
77
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
80
78
|
deadbeef = JIRA::Resource::Deadbeef.find(client, '98765')
|
@@ -84,16 +82,16 @@ describe JIRA::Base do
|
|
84
82
|
expect(deadbeef.expanded?).to be_truthy
|
85
83
|
end
|
86
84
|
|
87
|
-
it
|
85
|
+
it 'finds a deadbeef containing changelog by id' do
|
88
86
|
response = instance_double(
|
89
|
-
|
87
|
+
'Response',
|
90
88
|
body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
|
91
89
|
)
|
92
90
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
|
93
91
|
|
94
92
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
95
93
|
|
96
|
-
deadbeef = JIRA::Resource::Deadbeef.find(client, '98765',
|
94
|
+
deadbeef = JIRA::Resource::Deadbeef.find(client, '98765', expand: 'changelog')
|
97
95
|
expect(deadbeef.client).to eq(client)
|
98
96
|
expect(deadbeef.attrs['self']).to eq('http://deadbeef/')
|
99
97
|
expect(deadbeef.attrs['id']).to eq('98765')
|
@@ -101,60 +99,58 @@ describe JIRA::Base do
|
|
101
99
|
expect(deadbeef.attrs['changelog']['histories']).to eq([])
|
102
100
|
end
|
103
101
|
|
104
|
-
it
|
105
|
-
deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' =>
|
102
|
+
it 'builds a deadbeef' do
|
103
|
+
deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' => '98765')
|
106
104
|
expect(deadbeef.expanded?).to be_falsey
|
107
105
|
|
108
106
|
expect(deadbeef.client).to eq(client)
|
109
107
|
expect(deadbeef.attrs['id']).to eq('98765')
|
110
108
|
end
|
111
109
|
|
112
|
-
it
|
110
|
+
it 'returns the endpoint name' do
|
113
111
|
expect(subject.class.endpoint_name).to eq('deadbeef')
|
114
112
|
end
|
115
113
|
|
116
|
-
it
|
114
|
+
it 'returns the path_component' do
|
117
115
|
attrs['id'] = '123'
|
118
116
|
expect(subject.path_component).to eq('/deadbeef/123')
|
119
117
|
end
|
120
118
|
|
121
|
-
it
|
119
|
+
it 'returns the path component for unsaved instances' do
|
122
120
|
expect(subject.path_component).to eq('/deadbeef')
|
123
121
|
end
|
124
122
|
|
125
|
-
it
|
123
|
+
it 'converts to a symbol' do
|
126
124
|
expect(subject.to_sym).to eq(:deadbeef)
|
127
125
|
end
|
128
126
|
|
129
|
-
describe
|
130
|
-
|
127
|
+
describe 'collection_path' do
|
131
128
|
before(:each) do
|
132
|
-
expect(client).to receive(:options).and_return(:
|
129
|
+
expect(client).to receive(:options).and_return(rest_base_path: '/deadbeef/bar')
|
133
130
|
end
|
134
131
|
|
135
|
-
it
|
132
|
+
it 'returns the collection_path' do
|
136
133
|
expect(subject.collection_path).to eq('/deadbeef/bar/deadbeef')
|
137
134
|
end
|
138
135
|
|
139
|
-
it
|
136
|
+
it 'returns the collection_path with a prefix' do
|
140
137
|
expect(subject.collection_path('/baz/')).to eq('/deadbeef/bar/baz/deadbeef')
|
141
138
|
end
|
142
139
|
|
143
|
-
it
|
140
|
+
it 'has a class method that returns the collection_path' do
|
144
141
|
expect(subject.class.collection_path(client)).to eq('/deadbeef/bar/deadbeef')
|
145
142
|
end
|
146
143
|
end
|
147
144
|
|
148
|
-
it
|
149
|
-
expect(described_class.parse_json('{"foo":"bar"}')).to eq(
|
145
|
+
it 'parses json' do
|
146
|
+
expect(described_class.parse_json('{"foo":"bar"}')).to eq('foo' => 'bar')
|
150
147
|
end
|
151
148
|
|
152
|
-
describe
|
153
|
-
|
154
|
-
|
155
|
-
subject { JIRA::Resource::Deadbeef.new(client, :attrs => attrs) }
|
149
|
+
describe 'dynamic instance methods' do
|
150
|
+
let(:attrs) { { 'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy' } }
|
151
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
|
156
152
|
|
157
|
-
it
|
153
|
+
it 'responds to each of the top level attribute names' do
|
158
154
|
expect(subject).to respond_to(:foo)
|
159
155
|
expect(subject).to respond_to('flum')
|
160
156
|
expect(subject).to respond_to(:object_id)
|
@@ -169,39 +165,36 @@ describe JIRA::Base do
|
|
169
165
|
end
|
170
166
|
end
|
171
167
|
|
172
|
-
describe
|
173
|
-
|
174
|
-
subject { JIRA::Resource::Deadbeef.new(client, :attrs => {'id' => '98765'}) }
|
175
|
-
|
176
|
-
describe "not cached" do
|
168
|
+
describe 'fetch' do
|
169
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '98765' }) }
|
177
170
|
|
171
|
+
describe 'not cached' do
|
178
172
|
before(:each) do
|
179
|
-
response = instance_double(
|
173
|
+
response = instance_double('Response', body: '{"self":"http://deadbeef/","id":"98765"}')
|
180
174
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
|
181
175
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
182
176
|
end
|
183
177
|
|
184
|
-
it
|
178
|
+
it 'sets expanded to true after fetch' do
|
185
179
|
expect(subject.expanded?).to be_falsey
|
186
180
|
subject.fetch
|
187
181
|
expect(subject.expanded?).to be_truthy
|
188
182
|
end
|
189
183
|
|
190
|
-
it
|
184
|
+
it 'performs a fetch' do
|
191
185
|
expect(subject.expanded?).to be_falsey
|
192
186
|
subject.fetch
|
193
|
-
expect(subject.self).to eq(
|
194
|
-
expect(subject.id).to eq(
|
187
|
+
expect(subject.self).to eq('http://deadbeef/')
|
188
|
+
expect(subject.id).to eq('98765')
|
195
189
|
end
|
196
190
|
|
197
|
-
it
|
191
|
+
it 'performs a fetch if already fetched and force flag is true' do
|
198
192
|
subject.expanded = true
|
199
193
|
subject.fetch(true)
|
200
194
|
end
|
201
|
-
|
202
195
|
end
|
203
196
|
|
204
|
-
describe
|
197
|
+
describe 'cached' do
|
205
198
|
it "doesn't perform a fetch if already fetched" do
|
206
199
|
subject.expanded = true
|
207
200
|
expect(client).not_to receive(:get)
|
@@ -212,25 +205,24 @@ describe JIRA::Base do
|
|
212
205
|
context "with expand parameter 'changelog'" do
|
213
206
|
it "fetchs changelogs '" do
|
214
207
|
response = instance_double(
|
215
|
-
|
208
|
+
'Response',
|
216
209
|
body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
|
217
210
|
)
|
218
211
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
|
219
212
|
|
220
213
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
221
214
|
|
222
|
-
subject.fetch(false,
|
215
|
+
subject.fetch(false, expand: 'changelog')
|
223
216
|
|
224
|
-
expect(subject.self).to eq(
|
225
|
-
expect(subject.id).to eq(
|
217
|
+
expect(subject.self).to eq('http://deadbeef/')
|
218
|
+
expect(subject.id).to eq('98765')
|
226
219
|
expect(subject.changelog['histories']).to eq([])
|
227
220
|
end
|
228
221
|
end
|
229
222
|
end
|
230
223
|
|
231
|
-
describe
|
232
|
-
|
233
|
-
let(:response) { double() }
|
224
|
+
describe 'save' do
|
225
|
+
let(:response) { double }
|
234
226
|
|
235
227
|
subject { JIRA::Resource::Deadbeef.new(client) }
|
236
228
|
|
@@ -238,49 +230,49 @@ describe JIRA::Base do
|
|
238
230
|
expect(subject).to receive(:url).and_return('/foo/bar')
|
239
231
|
end
|
240
232
|
|
241
|
-
it
|
242
|
-
response = instance_double(
|
233
|
+
it 'POSTs a new record' do
|
234
|
+
response = instance_double('Response', body: '{"id":"123"}')
|
243
235
|
allow(subject).to receive(:new_record?) { true }
|
244
|
-
expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
|
245
|
-
expect(subject.save(
|
246
|
-
expect(subject.id).to eq(
|
236
|
+
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
237
|
+
expect(subject.save('foo' => 'bar')).to be_truthy
|
238
|
+
expect(subject.id).to eq('123')
|
247
239
|
expect(subject.expanded).to be_falsey
|
248
240
|
end
|
249
241
|
|
250
|
-
it
|
251
|
-
response = instance_double(
|
242
|
+
it 'PUTs an existing record' do
|
243
|
+
response = instance_double('Response', body: nil)
|
252
244
|
allow(subject).to receive(:new_record?) { false }
|
253
|
-
expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
|
254
|
-
expect(subject.save(
|
245
|
+
expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
246
|
+
expect(subject.save('foo' => 'bar')).to be_truthy
|
255
247
|
expect(subject.expanded).to be_falsey
|
256
248
|
end
|
257
249
|
|
258
|
-
it
|
259
|
-
response = instance_double(
|
260
|
-
expect(client).to receive(:post).with('/foo/bar','{"foo":{"fum":"dum"}}').and_return(response)
|
261
|
-
subject.attrs = {
|
262
|
-
subject.save(
|
263
|
-
expect(subject.foo).to eq(
|
250
|
+
it 'merges attrs on save' do
|
251
|
+
response = instance_double('Response', body: nil)
|
252
|
+
expect(client).to receive(:post).with('/foo/bar', '{"foo":{"fum":"dum"}}').and_return(response)
|
253
|
+
subject.attrs = { 'foo' => { 'bar' => 'baz' } }
|
254
|
+
subject.save('foo' => { 'fum' => 'dum' })
|
255
|
+
expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
|
264
256
|
end
|
265
257
|
|
266
|
-
it
|
267
|
-
response = instance_double(
|
258
|
+
it 'returns false when an invalid field is set' do # The JIRA REST API apparently ignores fields that you aren't allowed to set manually
|
259
|
+
response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
|
268
260
|
allow(subject).to receive(:new_record?) { false }
|
269
|
-
expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
270
|
-
expect(subject.save(
|
261
|
+
expect(client).to receive(:put).with('/foo/bar', '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
262
|
+
expect(subject.save('invalid_field' => 'foobar')).to be_falsey
|
271
263
|
end
|
272
264
|
|
273
|
-
it
|
274
|
-
response = double(
|
275
|
-
expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
|
276
|
-
expect(subject.save(
|
277
|
-
expect(subject.attrs[
|
278
|
-
expect(subject.attrs[
|
265
|
+
it 'returns false with exception details when non json response body (unauthorized)' do # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
|
266
|
+
response = double('Response', body: 'totally invalid json', code: 401, message: 'Unauthorized')
|
267
|
+
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
|
268
|
+
expect(subject.save('foo' => 'bar')).to be_falsey
|
269
|
+
expect(subject.attrs['exception']['code']).to eq(401)
|
270
|
+
expect(subject.attrs['exception']['message']).to eq('Unauthorized')
|
279
271
|
end
|
280
272
|
end
|
281
273
|
|
282
|
-
describe
|
283
|
-
let(:response) { double
|
274
|
+
describe 'save!' do
|
275
|
+
let(:response) { double }
|
284
276
|
|
285
277
|
subject { JIRA::Resource::Deadbeef.new(client) }
|
286
278
|
|
@@ -288,144 +280,137 @@ describe JIRA::Base do
|
|
288
280
|
expect(subject).to receive(:url).and_return('/foo/bar')
|
289
281
|
end
|
290
282
|
|
291
|
-
it
|
292
|
-
response = instance_double(
|
283
|
+
it 'POSTs a new record' do
|
284
|
+
response = instance_double('Response', body: '{"id":"123"}')
|
293
285
|
allow(subject).to receive(:new_record?) { true }
|
294
|
-
expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
|
295
|
-
expect(subject.save!(
|
296
|
-
expect(subject.id).to eq(
|
286
|
+
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
287
|
+
expect(subject.save!('foo' => 'bar')).to be_truthy
|
288
|
+
expect(subject.id).to eq('123')
|
297
289
|
expect(subject.expanded).to be_falsey
|
298
290
|
end
|
299
291
|
|
300
|
-
it
|
301
|
-
response = instance_double(
|
292
|
+
it 'PUTs an existing record' do
|
293
|
+
response = instance_double('Response', body: nil)
|
302
294
|
allow(subject).to receive(:new_record?) { false }
|
303
|
-
expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
|
304
|
-
expect(subject.save!(
|
295
|
+
expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
296
|
+
expect(subject.save!('foo' => 'bar')).to be_truthy
|
305
297
|
expect(subject.expanded).to be_falsey
|
306
298
|
end
|
307
299
|
|
308
|
-
it
|
309
|
-
response = instance_double(
|
300
|
+
it 'throws an exception when an invalid field is set' do
|
301
|
+
response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
|
310
302
|
allow(subject).to receive(:new_record?) { false }
|
311
|
-
expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
312
|
-
expect(
|
303
|
+
expect(client).to receive(:put).with('/foo/bar', '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
304
|
+
expect(-> { subject.save!('invalid_field' => 'foobar') }).to raise_error(JIRA::HTTPError)
|
313
305
|
end
|
314
306
|
end
|
315
307
|
|
316
|
-
describe
|
317
|
-
it
|
318
|
-
subject.attrs = {
|
319
|
-
subject.set_attrs(
|
320
|
-
expect(subject.foo).to eq(
|
308
|
+
describe 'set_attrs' do
|
309
|
+
it 'merges hashes correctly when clobber is true (default)' do
|
310
|
+
subject.attrs = { 'foo' => { 'bar' => 'baz' } }
|
311
|
+
subject.set_attrs('foo' => { 'fum' => 'dum' })
|
312
|
+
expect(subject.foo).to eq('fum' => 'dum')
|
321
313
|
end
|
322
314
|
|
323
|
-
it
|
324
|
-
subject.attrs = {
|
325
|
-
subject.set_attrs({
|
326
|
-
expect(subject.foo).to eq(
|
315
|
+
it 'merges hashes correctly when clobber is false' do
|
316
|
+
subject.attrs = { 'foo' => { 'bar' => 'baz' } }
|
317
|
+
subject.set_attrs({ 'foo' => { 'fum' => 'dum' } }, false)
|
318
|
+
expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
|
327
319
|
end
|
328
320
|
end
|
329
321
|
|
330
|
-
describe
|
331
|
-
|
322
|
+
describe 'delete' do
|
332
323
|
before(:each) do
|
333
324
|
expect(client).to receive(:delete).with('/foo/bar')
|
334
325
|
allow(subject).to receive(:url) { '/foo/bar' }
|
335
326
|
end
|
336
327
|
|
337
|
-
it
|
328
|
+
it 'flags itself as deleted' do
|
338
329
|
expect(subject.deleted?).to be_falsey
|
339
330
|
subject.delete
|
340
331
|
expect(subject.deleted?).to be_truthy
|
341
332
|
end
|
342
333
|
|
343
|
-
it
|
334
|
+
it 'sends a DELETE request' do
|
344
335
|
subject.delete
|
345
336
|
end
|
346
|
-
|
347
337
|
end
|
348
338
|
|
349
|
-
describe
|
350
|
-
|
351
|
-
it "returns true for new_record? when new object" do
|
339
|
+
describe 'new_record?' do
|
340
|
+
it 'returns true for new_record? when new object' do
|
352
341
|
subject.attrs['id'] = nil
|
353
342
|
expect(subject.new_record?).to be_truthy
|
354
343
|
end
|
355
344
|
|
356
|
-
it
|
345
|
+
it 'returns false for new_record? when id is set' do
|
357
346
|
subject.attrs['id'] = '123'
|
358
347
|
expect(subject.new_record?).to be_falsey
|
359
348
|
end
|
360
|
-
|
361
349
|
end
|
362
350
|
|
363
|
-
describe
|
364
|
-
|
365
|
-
|
366
|
-
attrs["errors"] = {"invalid" => "Field invalid"}
|
351
|
+
describe 'has_errors?' do
|
352
|
+
it 'returns true when the response contains errors' do
|
353
|
+
attrs['errors'] = { 'invalid' => 'Field invalid' }
|
367
354
|
expect(subject.has_errors?).to be_truthy
|
368
355
|
end
|
369
356
|
|
370
|
-
it
|
357
|
+
it 'returns false when the response does not contain any errors' do
|
371
358
|
expect(subject.has_errors?).to be_falsey
|
372
359
|
end
|
373
|
-
|
374
360
|
end
|
375
361
|
|
376
362
|
describe 'url' do
|
377
|
-
|
378
363
|
before(:each) do
|
379
|
-
allow(client).to receive(:options) { {:
|
364
|
+
allow(client).to receive(:options) { { rest_base_path: '/foo/bar' } }
|
380
365
|
end
|
381
366
|
|
382
|
-
it
|
367
|
+
it 'returns self as the URL if set' do
|
383
368
|
attrs['self'] = 'http://foo/bar'
|
384
|
-
expect(subject.url).to eq(
|
369
|
+
expect(subject.url).to eq('http://foo/bar')
|
385
370
|
end
|
386
371
|
|
387
|
-
it
|
372
|
+
it 'generates the URL from id if self not set' do
|
388
373
|
attrs['self'] = nil
|
389
374
|
attrs['id'] = '98765'
|
390
|
-
expect(subject.url).to eq(
|
375
|
+
expect(subject.url).to eq('/foo/bar/deadbeef/98765')
|
391
376
|
end
|
392
377
|
|
393
|
-
it
|
378
|
+
it 'generates the URL from collection_path if self and id not set' do
|
394
379
|
attrs['self'] = nil
|
395
|
-
attrs['id']
|
396
|
-
expect(subject.url).to eq(
|
380
|
+
attrs['id'] = nil
|
381
|
+
expect(subject.url).to eq('/foo/bar/deadbeef')
|
397
382
|
end
|
398
383
|
|
399
|
-
it
|
400
|
-
expect(JIRA::Resource::Deadbeef.collection_path(client)).to eq(
|
401
|
-
#Should accept an optional prefix (flum in this case)
|
402
|
-
expect(JIRA::Resource::Deadbeef.collection_path(client, '/flum/')).to eq(
|
384
|
+
it 'has a class method for the collection path' do
|
385
|
+
expect(JIRA::Resource::Deadbeef.collection_path(client)).to eq('/foo/bar/deadbeef')
|
386
|
+
# Should accept an optional prefix (flum in this case)
|
387
|
+
expect(JIRA::Resource::Deadbeef.collection_path(client, '/flum/')).to eq('/foo/bar/flum/deadbeef')
|
403
388
|
end
|
404
389
|
|
405
|
-
it
|
406
|
-
expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123')).to eq(
|
407
|
-
#Should accept an optional prefix (flum in this case)
|
408
|
-
expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123', '/flum/')).to eq(
|
390
|
+
it 'has a class method for the singular path' do
|
391
|
+
expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123')).to eq('/foo/bar/deadbeef/abc123')
|
392
|
+
# Should accept an optional prefix (flum in this case)
|
393
|
+
expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123', '/flum/')).to eq('/foo/bar/flum/deadbeef/abc123')
|
409
394
|
end
|
410
395
|
end
|
411
396
|
|
412
|
-
it
|
397
|
+
it 'returns the formatted attrs from to_s' do
|
413
398
|
subject.attrs['foo'] = 'bar'
|
414
399
|
subject.attrs['dead'] = 'beef'
|
415
400
|
|
416
401
|
expect(subject.to_s).to match(/#<JIRA::Resource::Deadbeef:\d+ @attrs=#{Regexp.quote(attrs.inspect)}>/)
|
417
402
|
end
|
418
403
|
|
419
|
-
it
|
404
|
+
it 'returns the key attribute' do
|
420
405
|
expect(subject.class.key_attribute).to eq(:id)
|
421
406
|
end
|
422
407
|
|
423
|
-
it
|
408
|
+
it 'returns the key value' do
|
424
409
|
subject.attrs['id'] = '123'
|
425
410
|
expect(subject.key_value).to eq('123')
|
426
411
|
end
|
427
412
|
|
428
|
-
it
|
413
|
+
it 'converts to json' do
|
429
414
|
subject.attrs = { 'foo' => 'bar', 'dead' => 'beef' }
|
430
415
|
expect(subject.to_json).to eq(subject.attrs.to_json)
|
431
416
|
|
@@ -434,53 +419,49 @@ describe JIRA::Base do
|
|
434
419
|
expect(h.to_json).to eq(h_attrs.to_json)
|
435
420
|
end
|
436
421
|
|
437
|
-
describe
|
438
|
-
|
439
|
-
subject { JIRA::Resource::Deadbeef.new(client, :attrs => {}) }
|
422
|
+
describe 'extract attrs from response' do
|
423
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs: {}) }
|
440
424
|
|
441
|
-
it
|
442
|
-
response = instance_double(
|
425
|
+
it 'sets the attrs from a response' do
|
426
|
+
response = instance_double('Response', body: '{"foo":"bar"}')
|
443
427
|
|
444
|
-
expect(subject.set_attrs_from_response(response)).to eq(
|
445
|
-
expect(subject.foo).to eq(
|
428
|
+
expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
|
429
|
+
expect(subject.foo).to eq('bar')
|
446
430
|
end
|
447
431
|
|
448
432
|
it "doesn't clobber existing attrs not in response" do
|
449
|
-
response = instance_double(
|
433
|
+
response = instance_double('Response', body: '{"foo":"bar"}')
|
450
434
|
|
451
|
-
subject.attrs = {'flum' => 'flar'}
|
452
|
-
expect(subject.set_attrs_from_response(response)).to eq(
|
453
|
-
expect(subject.foo).to eq(
|
454
|
-
expect(subject.flum).to eq(
|
435
|
+
subject.attrs = { 'flum' => 'flar' }
|
436
|
+
expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
|
437
|
+
expect(subject.foo).to eq('bar')
|
438
|
+
expect(subject.flum).to eq('flar')
|
455
439
|
end
|
456
440
|
|
457
|
-
it
|
458
|
-
response = instance_double(
|
441
|
+
it 'handles nil response body' do
|
442
|
+
response = instance_double('Response', body: nil)
|
459
443
|
|
460
|
-
subject.attrs = {'flum' => 'flar'}
|
444
|
+
subject.attrs = { 'flum' => 'flar' }
|
461
445
|
expect(subject.set_attrs_from_response(response)).to be_nil
|
462
446
|
expect(subject.flum).to eq('flar')
|
463
447
|
end
|
464
448
|
end
|
465
449
|
|
466
|
-
describe
|
467
|
-
|
468
|
-
it "defaults collection_attributes_are_nested to false" do
|
450
|
+
describe 'nesting' do
|
451
|
+
it 'defaults collection_attributes_are_nested to false' do
|
469
452
|
expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_falsey
|
470
453
|
end
|
471
454
|
|
472
|
-
it
|
455
|
+
it 'allows collection_attributes_are_nested to be set' do
|
473
456
|
JIRA::Resource::Deadbeef.nested_collections true
|
474
457
|
expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_truthy
|
475
458
|
end
|
476
|
-
|
477
459
|
end
|
478
460
|
|
479
|
-
describe
|
461
|
+
describe 'has_many' do
|
462
|
+
subject { JIRA::Resource::HasManyExample.new(client, attrs: { 'deadbeefs' => [{ 'id' => '123' }] }) }
|
480
463
|
|
481
|
-
|
482
|
-
|
483
|
-
it "returns a collection of instances for has_many relationships" do
|
464
|
+
it 'returns a collection of instances for has_many relationships' do
|
484
465
|
expect(subject.deadbeefs.class).to eq(JIRA::HasManyProxy)
|
485
466
|
expect(subject.deadbeefs.length).to eq(1)
|
486
467
|
subject.deadbeefs.each do |deadbeef|
|
@@ -488,123 +469,118 @@ describe JIRA::Base do
|
|
488
469
|
end
|
489
470
|
end
|
490
471
|
|
491
|
-
it
|
472
|
+
it 'returns an empty collection for empty has_many relationships' do
|
492
473
|
subject = JIRA::Resource::HasManyExample.new(client)
|
493
474
|
expect(subject.deadbeefs.length).to eq(0)
|
494
475
|
end
|
495
476
|
|
496
|
-
it
|
497
|
-
subject = JIRA::Resource::HasManyExample.new(client, :
|
477
|
+
it 'allows the has_many attributes to be nested inside another attribute' do
|
478
|
+
subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'nested' => { 'brunchmuffins' => [{ 'id' => '123' }, { 'id' => '456' }] } })
|
498
479
|
expect(subject.brunchmuffins.length).to eq(2)
|
499
480
|
subject.brunchmuffins.each do |brunchmuffin|
|
500
481
|
expect(brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
|
501
482
|
end
|
502
483
|
end
|
503
484
|
|
504
|
-
it
|
505
|
-
subject = JIRA::Resource::HasManyExample.new(client, :
|
506
|
-
|
507
|
-
|
485
|
+
it 'allows it to be deeply nested' do
|
486
|
+
subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'nested' => {
|
487
|
+
'breakfastscone' => { 'breakfastscones' => [{ 'id' => '123' }, { 'id' => '456' }] }
|
488
|
+
} })
|
508
489
|
expect(subject.breakfastscones.length).to eq(2)
|
509
490
|
subject.breakfastscones.each do |breakfastscone|
|
510
491
|
expect(breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
|
511
492
|
end
|
512
493
|
end
|
513
494
|
|
514
|
-
it
|
515
|
-
subject = JIRA::Resource::HasManyExample.new(client, :
|
516
|
-
|
517
|
-
|
495
|
+
it 'short circuits missing deeply nested attrs' do
|
496
|
+
subject = JIRA::Resource::HasManyExample.new(client, attrs: {
|
497
|
+
'nested' => {}
|
498
|
+
})
|
518
499
|
expect(subject.breakfastscones.length).to eq(0)
|
519
500
|
end
|
520
501
|
|
521
|
-
it
|
522
|
-
subject = JIRA::Resource::HasManyExample.new(client, :
|
502
|
+
it 'allows the attribute key to be specified' do
|
503
|
+
subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'irregularlyNamedThings' => [{ 'id' => '123' }, { 'id' => '456' }] })
|
523
504
|
expect(subject.irregularly_named_things.length).to eq(2)
|
524
505
|
subject.irregularly_named_things.each do |thing|
|
525
506
|
expect(thing.class).to eq(JIRA::Resource::Deadbeef)
|
526
507
|
end
|
527
508
|
end
|
528
509
|
|
529
|
-
it
|
510
|
+
it 'can build child instances' do
|
530
511
|
deadbeef = subject.deadbeefs.build
|
531
512
|
expect(deadbeef.class).to eq(JIRA::Resource::Deadbeef)
|
532
513
|
end
|
533
|
-
|
534
514
|
end
|
535
515
|
|
536
|
-
describe
|
537
|
-
|
538
|
-
subject { JIRA::Resource::HasOneExample.new(client, :attrs => {'deadbeef' => {'id' => '123'}}) }
|
516
|
+
describe 'has_one' do
|
517
|
+
subject { JIRA::Resource::HasOneExample.new(client, attrs: { 'deadbeef' => { 'id' => '123' } }) }
|
539
518
|
|
540
|
-
it
|
519
|
+
it 'returns an instance for a has one relationship' do
|
541
520
|
expect(subject.deadbeef.class).to eq(JIRA::Resource::Deadbeef)
|
542
521
|
expect(subject.deadbeef.id).to eq('123')
|
543
522
|
end
|
544
523
|
|
545
|
-
it
|
524
|
+
it 'returns nil when resource attribute is nonexistent' do
|
546
525
|
subject = JIRA::Resource::HasOneExample.new(client)
|
547
526
|
expect(subject.deadbeef).to be_nil
|
548
527
|
end
|
549
528
|
|
550
|
-
it
|
551
|
-
subject = JIRA::Resource::HasOneExample.new(client, :
|
529
|
+
it 'returns an instance with a different class name to the attribute name' do
|
530
|
+
subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'muffin' => { 'id' => '123' } })
|
552
531
|
expect(subject.muffin.class).to eq(JIRA::Resource::Deadbeef)
|
553
532
|
expect(subject.muffin.id).to eq('123')
|
554
533
|
end
|
555
534
|
|
556
|
-
it
|
557
|
-
subject = JIRA::Resource::HasOneExample.new(client, :
|
535
|
+
it 'allows the has_one attributes to be nested inside another attribute' do
|
536
|
+
subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'nested' => { 'brunchmuffin' => { 'id' => '123' } } })
|
558
537
|
expect(subject.brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
|
559
538
|
expect(subject.brunchmuffin.id).to eq('123')
|
560
539
|
end
|
561
540
|
|
562
|
-
it
|
563
|
-
subject = JIRA::Resource::HasOneExample.new(client, :
|
564
|
-
|
565
|
-
|
541
|
+
it 'allows it to be deeply nested' do
|
542
|
+
subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'nested' => {
|
543
|
+
'breakfastscone' => { 'breakfastscone' => { 'id' => '123' } }
|
544
|
+
} })
|
566
545
|
expect(subject.breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
|
567
546
|
expect(subject.breakfastscone.id).to eq('123')
|
568
547
|
end
|
569
548
|
|
570
|
-
it
|
571
|
-
subject = JIRA::Resource::HasOneExample.new(client, :
|
549
|
+
it 'allows the attribute key to be specified' do
|
550
|
+
subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'irregularlyNamedThing' => { 'id' => '123' } })
|
572
551
|
expect(subject.irregularly_named_thing.class).to eq(JIRA::Resource::Deadbeef)
|
573
552
|
expect(subject.irregularly_named_thing.id).to eq('123')
|
574
553
|
end
|
575
|
-
|
576
554
|
end
|
577
555
|
|
578
|
-
describe
|
579
|
-
|
556
|
+
describe 'belongs_to' do
|
580
557
|
class JIRA::Resource::BelongsToExample < JIRA::Base
|
581
558
|
belongs_to :deadbeef
|
582
559
|
end
|
583
560
|
|
584
|
-
let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, :
|
561
|
+
let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '999' }) }
|
585
562
|
|
586
|
-
subject { JIRA::Resource::BelongsToExample.new(client, :
|
563
|
+
subject { JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef: deadbeef) }
|
587
564
|
|
588
|
-
it
|
565
|
+
it 'sets up an accessor for the belongs to relationship' do
|
589
566
|
expect(subject.deadbeef).to eq(deadbeef)
|
590
567
|
end
|
591
568
|
|
592
|
-
it
|
569
|
+
it 'raises an exception when initialized without a belongs_to instance' do
|
593
570
|
expect(lambda {
|
594
|
-
JIRA::Resource::BelongsToExample.new(client, :
|
595
|
-
}).to raise_exception(ArgumentError,
|
571
|
+
JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' })
|
572
|
+
}).to raise_exception(ArgumentError, 'Required option :deadbeef missing')
|
596
573
|
end
|
597
574
|
|
598
|
-
it
|
599
|
-
allow(client).to receive(:options) { { :
|
600
|
-
expect(subject.url).to eq(
|
575
|
+
it 'returns the right url' do
|
576
|
+
allow(client).to receive(:options) { { rest_base_path: '/foo' } }
|
577
|
+
expect(subject.url).to eq('/foo/deadbeef/999/belongstoexample/123')
|
601
578
|
end
|
602
579
|
|
603
|
-
it
|
604
|
-
allow(client).to receive(:options) { { :
|
605
|
-
subject = JIRA::Resource::BelongsToExample.new(client, :
|
606
|
-
expect(subject.url).to eq(
|
580
|
+
it 'can be initialized with an instance or a key value' do
|
581
|
+
allow(client).to receive(:options) { { rest_base_path: '/foo' } }
|
582
|
+
subject = JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef_id: '987')
|
583
|
+
expect(subject.url).to eq('/foo/deadbeef/987/belongstoexample/123')
|
607
584
|
end
|
608
|
-
|
609
585
|
end
|
610
586
|
end
|