jira-ruby 1.5.0 → 1.6.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.
- 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
|