jira-ruby 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jira::Resource::BaseFactory do
4
+
5
+ class Jira::Resource::FooFactory < Jira::Resource::BaseFactory ; end
6
+ class Jira::Resource::Foo ; end
7
+
8
+ let(:client) { mock() }
9
+ subject { Jira::Resource::FooFactory.new(client) }
10
+
11
+ it "initializes correctly" do
12
+ subject.class.should == Jira::Resource::FooFactory
13
+ subject.client.should == client
14
+ subject.target_class.should == Jira::Resource::Foo
15
+ end
16
+
17
+ it "proxies all to the target class" do
18
+ Jira::Resource::Foo.should_receive(:all).with(client)
19
+ subject.all
20
+ end
21
+
22
+ it "proxies find to the target class" do
23
+ Jira::Resource::Foo.should_receive(:find).with(client, 'FOO')
24
+ subject.find('FOO')
25
+ end
26
+
27
+ it "returns the target class" do
28
+ subject.target_class.should == Jira::Resource::Foo
29
+ end
30
+
31
+ it "proxies build to the target class" do
32
+ attrs = mock()
33
+ Jira::Resource::Foo.should_receive(:build).with(client, attrs)
34
+ subject.build(attrs)
35
+ end
36
+ end
@@ -0,0 +1,292 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jira::Resource::Base do
4
+
5
+ class Jira::Resource::Deadbeef < Jira::Resource::Base ; end
6
+
7
+ let(:client) { mock() }
8
+ let(:attrs) { mock() }
9
+
10
+ subject { Jira::Resource::Deadbeef.new(client, :attrs => attrs) }
11
+
12
+ it "assigns the client and attrs" do
13
+ subject.client.should == client
14
+ subject.attrs.should == attrs
15
+ end
16
+
17
+ it "returns all the deadbeefs" do
18
+ response = mock()
19
+ response.should_receive(:body).and_return('[{"self":"http://deadbeef/","key":"FOO"}]')
20
+ client.should_receive(:get).with('/jira/rest/api/2/deadbeef').and_return(response)
21
+ Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
22
+ deadbeefs = Jira::Resource::Deadbeef.all(client)
23
+ deadbeefs.length.should == 1
24
+ first = deadbeefs.first
25
+ first.class.should == Jira::Resource::Deadbeef
26
+ first.attrs['self'].should == 'http://deadbeef/'
27
+ first.attrs['key'].should == 'FOO'
28
+ first.expanded?.should be_false
29
+ end
30
+
31
+ it "finds a deadbeef by key" do
32
+ response = mock()
33
+ response.stub(:body).and_return('{"self":"http://deadbeef/","key":"FOO"}')
34
+ client.should_receive(:get).with('/jira/rest/api/2/deadbeef/FOO').and_return(response)
35
+ Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
36
+ deadbeef = Jira::Resource::Deadbeef.find(client, 'FOO')
37
+ deadbeef.client.should == client
38
+ deadbeef.attrs['self'].should == 'http://deadbeef/'
39
+ deadbeef.attrs['key'].should == 'FOO'
40
+ deadbeef.expanded?.should be_true
41
+ end
42
+
43
+ it "builds a deadbeef" do
44
+ deadbeef = Jira::Resource::Deadbeef.build(client, 'key' => "FOO" )
45
+ deadbeef.expanded?.should be_false
46
+
47
+ deadbeef.client.should == client
48
+ deadbeef.attrs['key'].should == 'FOO'
49
+ end
50
+
51
+ it "returns the endpoint name" do
52
+ subject.class.endpoint_name.should == 'deadbeef'
53
+ end
54
+
55
+
56
+ describe "rest_base_path" do
57
+
58
+ before(:each) do
59
+ client.should_receive(:options).and_return(:rest_base_path => '/deadbeef/bar')
60
+ end
61
+
62
+ it "returns the rest_base_path" do
63
+ subject.rest_base_path.should == '/deadbeef/bar/deadbeef'
64
+ end
65
+
66
+ it "has a class method that returns the rest_base_path" do
67
+ subject.class.rest_base_path(client).should == '/deadbeef/bar/deadbeef'
68
+ end
69
+ end
70
+
71
+ it "parses json" do
72
+ described_class.parse_json('{"foo":"bar"}').should == {"foo" => "bar"}
73
+ end
74
+
75
+ describe "dynamic instance methods" do
76
+
77
+ let(:attrs) { {'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy'} }
78
+ subject { Jira::Resource::Deadbeef.new(client, :attrs => attrs) }
79
+
80
+ it "responds to each of the top level attribute names" do
81
+ subject.should respond_to(:foo)
82
+ subject.should respond_to('flum')
83
+ subject.should respond_to(:object_id)
84
+
85
+ subject.foo.should == 'bar'
86
+ subject.flum.should == 'goo'
87
+
88
+ # Should not override existing method names, but should still allow
89
+ # access to their values via the attrs[] hash
90
+ subject.object_id.should_not == 'dummy'
91
+ subject.attrs['object_id'].should == 'dummy'
92
+ end
93
+ end
94
+
95
+ describe "fetch" do
96
+
97
+ subject { Jira::Resource::Deadbeef.new(client, :attrs => {'key' => 'FOO'}) }
98
+
99
+ describe "not cached" do
100
+
101
+ before(:each) do
102
+ response = mock()
103
+ response.stub(:body).and_return('{"self":"http://deadbeef/","key":"FOO"}')
104
+ client.should_receive(:get).with('/jira/rest/api/2/deadbeef/FOO').and_return(response)
105
+ Jira::Resource::Deadbeef.should_receive(:rest_base_path).and_return('/jira/rest/api/2/deadbeef')
106
+ end
107
+
108
+ it "sets expanded to true after fetch" do
109
+ subject.expanded?.should be_false
110
+ subject.fetch
111
+ subject.expanded?.should be_true
112
+ end
113
+
114
+ it "performs a fetch" do
115
+ subject.expanded?.should be_false
116
+ subject.fetch
117
+ subject.self.should == "http://deadbeef/"
118
+ subject.key.should == "FOO"
119
+ end
120
+
121
+ it "performs a fetch if already fetched and force flag is true" do
122
+ subject.expanded = true
123
+ subject.fetch(true)
124
+ end
125
+
126
+ end
127
+
128
+ describe "cached" do
129
+ it "doesn't perform a fetch if already fetched" do
130
+ subject.expanded = true
131
+ client.should_not_receive(:get)
132
+ subject.fetch
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ describe "save" do
139
+
140
+ let(:response) { mock() }
141
+
142
+ subject { Jira::Resource::Deadbeef.new(client) }
143
+
144
+ before(:each) do
145
+ subject.should_receive(:url).and_return('/foo/bar')
146
+ end
147
+
148
+ it "POSTs a new record" do
149
+ response.stub(:body => '{"id":"123"}')
150
+ subject.stub(:new_record? => true)
151
+ client.should_receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
152
+ subject.save("foo" => "bar").should be_true
153
+ subject.id.should == "123"
154
+ subject.expanded.should be_false
155
+ end
156
+
157
+ it "PUTs an existing record" do
158
+ response.stub(:body => nil)
159
+ subject.stub(:new_record? => false)
160
+ client.should_receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
161
+ subject.save("foo" => "bar").should be_true
162
+ subject.expanded.should be_false
163
+ end
164
+
165
+ it "merges attrs on save" do
166
+ response.stub(:body => nil)
167
+ client.should_receive(:post).with('/foo/bar','{"foo":{"fum":"dum"}}').and_return(response)
168
+ subject.attrs = {"foo" => {"bar" => "baz"}}
169
+ subject.save({"foo" => {"fum" => "dum"}})
170
+ subject.foo.should == {"bar" => "baz", "fum" => "dum"}
171
+ end
172
+
173
+ end
174
+
175
+ describe "set_attrs" do
176
+ it "merges hashes correctly when clobber is true (default)" do
177
+ subject.attrs = {"foo" => {"bar" => "baz"}}
178
+ subject.set_attrs({"foo" => {"fum" => "dum"}})
179
+ subject.foo.should == {"fum" => "dum"}
180
+ end
181
+
182
+ it "merges hashes correctly when clobber is false" do
183
+ subject.attrs = {"foo" => {"bar" => "baz"}}
184
+ subject.set_attrs({"foo" => {"fum" => "dum"}}, false)
185
+ subject.foo.should == {"bar" => "baz", "fum" => "dum"}
186
+ end
187
+ end
188
+
189
+ describe "delete" do
190
+
191
+ before(:each) do
192
+ client.should_receive(:delete).with('/foo/bar')
193
+ subject.stub(:url => '/foo/bar')
194
+ end
195
+
196
+ it "flags itself as deleted" do
197
+ subject.deleted?.should be_false
198
+ subject.delete
199
+ subject.deleted?.should be_true
200
+ end
201
+
202
+ it "sends a DELETE request" do
203
+ subject.delete
204
+ end
205
+
206
+ end
207
+
208
+ describe "new_record?" do
209
+
210
+ it "returns true for new_record? when new object" do
211
+ subject.attrs.stub(:[]).with('id').and_return(nil)
212
+ subject.new_record?.should be_true
213
+ end
214
+
215
+ it "returns false for new_record? when id is set" do
216
+ subject.attrs.stub(:[]).with('id').and_return('123')
217
+ subject.new_record?.should be_false
218
+ end
219
+
220
+ end
221
+
222
+ describe 'url' do
223
+ it "returns self as the URL if set" do
224
+ attrs.stub(:[]).with('self').and_return('http://foo/bar')
225
+ subject.url.should == "http://foo/bar"
226
+ end
227
+
228
+ it "generates the URL from key if self not set" do
229
+ attrs.stub(:[]).with('self').and_return(nil)
230
+ attrs.stub(:[]).with('key').and_return('FOO')
231
+ subject.stub(:rest_base_path => 'http://foo/bar')
232
+ subject.url.should == "http://foo/bar/FOO"
233
+ end
234
+
235
+ it "generates the URL from rest_base_path if self and key not set" do
236
+ attrs.stub(:[]).with('self').and_return(nil)
237
+ attrs.stub(:[]).with('key').and_return(nil)
238
+ subject.stub(:rest_base_path => 'http://foo/bar')
239
+ subject.url.should == "http://foo/bar"
240
+ end
241
+ end
242
+
243
+ it "returns the formatted attrs from to_s" do
244
+ subject.attrs.stub(:[]).with('foo').and_return('bar')
245
+ subject.attrs.stub(:[]).with('dead').and_return('beef')
246
+
247
+ subject.to_s.should match(/#<Jira::Resource::Deadbeef:\d+ @attrs=#{attrs.inspect}>/)
248
+ end
249
+
250
+ it "returns the key attribute" do
251
+ subject.class.key_attribute.should == :key
252
+ end
253
+
254
+ it "converts to json" do
255
+ subject.attrs.stub(:to_json => '{"foo":"bar","dead":"beef"}')
256
+
257
+ subject.to_json.should == '{"foo":"bar","dead":"beef"}'
258
+ end
259
+
260
+ describe "extract attrs from response" do
261
+
262
+ subject { Jira::Resource::Deadbeef.new(client, :attrs => {}) }
263
+
264
+ it "sets the attrs from a response" do
265
+ response = mock()
266
+ response.stub(:body).and_return('{"foo":"bar"}')
267
+
268
+ subject.set_attrs_from_response(response).should == {'foo' => 'bar'}
269
+ subject.foo.should == "bar"
270
+ end
271
+
272
+ it "doesn't clobber existing attrs not in response" do
273
+ response = mock()
274
+ response.stub(:body).and_return('{"foo":"bar"}')
275
+
276
+ subject.attrs = {'flum' => 'flar'}
277
+ subject.set_attrs_from_response(response).should == {'foo' => 'bar'}
278
+ subject.foo.should == "bar"
279
+ subject.flum.should == "flar"
280
+ end
281
+
282
+ it "handles nil response body" do
283
+ response = mock()
284
+ response.stub(:body).and_return(nil)
285
+
286
+ subject.attrs = {'flum' => 'flar'}
287
+ subject.set_attrs_from_response(response).should be_nil
288
+ subject.flum.should == 'flar'
289
+ end
290
+ end
291
+
292
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jira::Resource::HTTPError do
4
+
5
+ let(:response) {
6
+ response = mock("response")
7
+ response.stub(:code => 401)
8
+ response.stub(:message => "A MESSAGE WOO")
9
+ response
10
+ }
11
+ subject { described_class.new(response) }
12
+
13
+ it "takes the response object as an argument" do
14
+ subject.response.should == response
15
+ end
16
+
17
+ it "has a code method" do
18
+ subject.code.should == response.code
19
+ end
20
+
21
+ it "returns code and class from message" do
22
+ subject.message.should == response.message
23
+ end
24
+
25
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jira::Resource::ProjectFactory do
4
+
5
+ let(:client) { mock() }
6
+ subject { Jira::Resource::ProjectFactory.new(client) }
7
+
8
+ it "initializes correctly" do
9
+ subject.class.should == Jira::Resource::ProjectFactory
10
+ subject.client.should == client
11
+ end
12
+
13
+ end
@@ -0,0 +1,28 @@
1
+ {
2
+ "self": "http://localhost:2990/jira/rest/api/2/component/10001",
3
+ "id": "10001",
4
+ "name": "Test component",
5
+ "assigneeType": "PROJECT_DEFAULT",
6
+ "assignee": {
7
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
8
+ "name": "admin",
9
+ "avatarUrls": {
10
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
11
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
12
+ },
13
+ "displayName": "admin",
14
+ "active": true
15
+ },
16
+ "realAssigneeType": "PROJECT_DEFAULT",
17
+ "realAssignee": {
18
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
19
+ "name": "admin",
20
+ "avatarUrls": {
21
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
22
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
23
+ },
24
+ "displayName": "admin",
25
+ "active": true
26
+ },
27
+ "isAssigneeTypeValid": true
28
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "self": "http://localhost:2990/jira/rest/api/2/component/10000",
3
+ "id": "10000",
4
+ "name": "Cheesecake",
5
+ "description": "Description!",
6
+ "lead": {
7
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
8
+ "name": "admin",
9
+ "avatarUrls": {
10
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
11
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
12
+ },
13
+ "displayName": "admin",
14
+ "active": true
15
+ },
16
+ "assigneeType": "PROJECT_DEFAULT",
17
+ "assignee": {
18
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
19
+ "name": "admin",
20
+ "avatarUrls": {
21
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
22
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
23
+ },
24
+ "displayName": "admin",
25
+ "active": true
26
+ },
27
+ "realAssigneeType": "PROJECT_DEFAULT",
28
+ "realAssignee": {
29
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
30
+ "name": "admin",
31
+ "avatarUrls": {
32
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
33
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
34
+ },
35
+ "displayName": "admin",
36
+ "active": true
37
+ },
38
+ "isAssigneeTypeValid": true
39
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "self": "http://localhost:2990/jira/rest/api/2/component/10000",
3
+ "id": "10000",
4
+ "name": "Jammy",
5
+ "description": "Description!",
6
+ "lead": {
7
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
8
+ "name": "admin",
9
+ "avatarUrls": {
10
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
11
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
12
+ },
13
+ "displayName": "admin",
14
+ "active": true
15
+ },
16
+ "assigneeType": "PROJECT_DEFAULT",
17
+ "assignee": {
18
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
19
+ "name": "admin",
20
+ "avatarUrls": {
21
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
22
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
23
+ },
24
+ "displayName": "admin",
25
+ "active": true
26
+ },
27
+ "realAssigneeType": "PROJECT_DEFAULT",
28
+ "realAssignee": {
29
+ "self": "http://localhost:2990/jira/rest/api/2/user?username=admin",
30
+ "name": "admin",
31
+ "avatarUrls": {
32
+ "16x16": "http://localhost:2990/jira/secure/useravatar?size=small&avatarId=10122",
33
+ "48x48": "http://localhost:2990/jira/secure/useravatar?avatarId=10122"
34
+ },
35
+ "displayName": "admin",
36
+ "active": true
37
+ },
38
+ "isAssigneeTypeValid": true
39
+ }