##// END OF EJS Templates
Adds assertions on response status and body....
Jean-Philippe Lang -
r9793:54d55a360a21
parent child
Show More
@@ -1,779 +1,764
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :versions,
28 :versions,
29 :trackers,
29 :trackers,
30 :projects_trackers,
30 :projects_trackers,
31 :issue_categories,
31 :issue_categories,
32 :enabled_modules,
32 :enabled_modules,
33 :enumerations,
33 :enumerations,
34 :attachments,
34 :attachments,
35 :workflows,
35 :workflows,
36 :custom_fields,
36 :custom_fields,
37 :custom_values,
37 :custom_values,
38 :custom_fields_projects,
38 :custom_fields_projects,
39 :custom_fields_trackers,
39 :custom_fields_trackers,
40 :time_entries,
40 :time_entries,
41 :journals,
41 :journals,
42 :journal_details,
42 :journal_details,
43 :queries,
43 :queries,
44 :attachments
44 :attachments
45
45
46 def setup
46 def setup
47 Setting.rest_api_enabled = '1'
47 Setting.rest_api_enabled = '1'
48 end
48 end
49
49
50 context "/issues" do
50 context "/issues" do
51 # Use a private project to make sure auth is really working and not just
51 # Use a private project to make sure auth is really working and not just
52 # only showing public issues.
52 # only showing public issues.
53 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
53 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
54
54
55 should "contain metadata" do
55 should "contain metadata" do
56 get '/issues.xml'
56 get '/issues.xml'
57
57
58 assert_tag :tag => 'issues',
58 assert_tag :tag => 'issues',
59 :attributes => {
59 :attributes => {
60 :type => 'array',
60 :type => 'array',
61 :total_count => assigns(:issue_count),
61 :total_count => assigns(:issue_count),
62 :limit => 25,
62 :limit => 25,
63 :offset => 0
63 :offset => 0
64 }
64 }
65 end
65 end
66
66
67 context "with offset and limit" do
67 context "with offset and limit" do
68 should "use the params" do
68 should "use the params" do
69 get '/issues.xml?offset=2&limit=3'
69 get '/issues.xml?offset=2&limit=3'
70
70
71 assert_equal 3, assigns(:limit)
71 assert_equal 3, assigns(:limit)
72 assert_equal 2, assigns(:offset)
72 assert_equal 2, assigns(:offset)
73 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
73 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
74 end
74 end
75 end
75 end
76
76
77 context "with nometa param" do
77 context "with nometa param" do
78 should "not contain metadata" do
78 should "not contain metadata" do
79 get '/issues.xml?nometa=1'
79 get '/issues.xml?nometa=1'
80
80
81 assert_tag :tag => 'issues',
81 assert_tag :tag => 'issues',
82 :attributes => {
82 :attributes => {
83 :type => 'array',
83 :type => 'array',
84 :total_count => nil,
84 :total_count => nil,
85 :limit => nil,
85 :limit => nil,
86 :offset => nil
86 :offset => nil
87 }
87 }
88 end
88 end
89 end
89 end
90
90
91 context "with nometa header" do
91 context "with nometa header" do
92 should "not contain metadata" do
92 should "not contain metadata" do
93 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
93 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
94
94
95 assert_tag :tag => 'issues',
95 assert_tag :tag => 'issues',
96 :attributes => {
96 :attributes => {
97 :type => 'array',
97 :type => 'array',
98 :total_count => nil,
98 :total_count => nil,
99 :limit => nil,
99 :limit => nil,
100 :offset => nil
100 :offset => nil
101 }
101 }
102 end
102 end
103 end
103 end
104
104
105 context "with relations" do
105 context "with relations" do
106 should "display relations" do
106 should "display relations" do
107 get '/issues.xml?include=relations'
107 get '/issues.xml?include=relations'
108
108
109 assert_response :success
109 assert_response :success
110 assert_equal 'application/xml', @response.content_type
110 assert_equal 'application/xml', @response.content_type
111 assert_tag 'relations',
111 assert_tag 'relations',
112 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
112 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
113 :children => {:count => 1},
113 :children => {:count => 1},
114 :child => {
114 :child => {
115 :tag => 'relation',
115 :tag => 'relation',
116 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
116 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
117 }
117 }
118 assert_tag 'relations',
118 assert_tag 'relations',
119 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
119 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
120 :children => {:count => 0}
120 :children => {:count => 0}
121 end
121 end
122 end
122 end
123
123
124 context "with invalid query params" do
124 context "with invalid query params" do
125 should "return errors" do
125 should "return errors" do
126 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
126 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
127
127
128 assert_response :unprocessable_entity
128 assert_response :unprocessable_entity
129 assert_equal 'application/xml', @response.content_type
129 assert_equal 'application/xml', @response.content_type
130 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
130 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
131 end
131 end
132 end
132 end
133
133
134 context "with custom field filter" do
134 context "with custom field filter" do
135 should "show only issues with the custom field value" do
135 should "show only issues with the custom field value" do
136 get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}}
136 get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}}
137
137
138 expected_ids = Issue.visible.all(
138 expected_ids = Issue.visible.all(
139 :include => :custom_values,
139 :include => :custom_values,
140 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
140 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
141
141
142 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
142 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
143 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
143 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
144 end
144 end
145 end
145 end
146 end
146 end
147
147
148 context "with custom field filter (shorthand method)" do
148 context "with custom field filter (shorthand method)" do
149 should "show only issues with the custom field value" do
149 should "show only issues with the custom field value" do
150 get '/issues.xml', { :cf_1 => 'MySQL' }
150 get '/issues.xml', { :cf_1 => 'MySQL' }
151
151
152 expected_ids = Issue.visible.all(
152 expected_ids = Issue.visible.all(
153 :include => :custom_values,
153 :include => :custom_values,
154 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
154 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
155
155
156 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
156 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
157 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
157 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
158 end
158 end
159 end
159 end
160 end
160 end
161 end
161 end
162
162
163 context "/index.json" do
163 context "/index.json" do
164 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
164 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
165 end
165 end
166
166
167 context "/index.xml with filter" do
167 context "/index.xml with filter" do
168 should "show only issues with the status_id" do
168 should "show only issues with the status_id" do
169 get '/issues.xml?status_id=5'
169 get '/issues.xml?status_id=5'
170
170
171 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
171 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
172
172
173 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
173 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
174 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
174 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
175 end
175 end
176 end
176 end
177 end
177 end
178
178
179 context "/index.json with filter" do
179 context "/index.json with filter" do
180 should "show only issues with the status_id" do
180 should "show only issues with the status_id" do
181 get '/issues.json?status_id=5'
181 get '/issues.json?status_id=5'
182
182
183 json = ActiveSupport::JSON.decode(response.body)
183 json = ActiveSupport::JSON.decode(response.body)
184 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
184 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
185 assert_equal 3, status_ids_used.length
185 assert_equal 3, status_ids_used.length
186 assert status_ids_used.all? {|id| id == 5 }
186 assert status_ids_used.all? {|id| id == 5 }
187 end
187 end
188
188
189 end
189 end
190
190
191 # Issue 6 is on a private project
191 # Issue 6 is on a private project
192 context "/issues/6.xml" do
192 context "/issues/6.xml" do
193 should_allow_api_authentication(:get, "/issues/6.xml")
193 should_allow_api_authentication(:get, "/issues/6.xml")
194 end
194 end
195
195
196 context "/issues/6.json" do
196 context "/issues/6.json" do
197 should_allow_api_authentication(:get, "/issues/6.json")
197 should_allow_api_authentication(:get, "/issues/6.json")
198 end
198 end
199
199
200 context "GET /issues/:id" do
200 context "GET /issues/:id" do
201 context "with journals" do
201 context "with journals" do
202 context ".xml" do
202 context ".xml" do
203 should "display journals" do
203 should "display journals" do
204 get '/issues/1.xml?include=journals'
204 get '/issues/1.xml?include=journals'
205
205
206 assert_tag :tag => 'issue',
206 assert_tag :tag => 'issue',
207 :child => {
207 :child => {
208 :tag => 'journals',
208 :tag => 'journals',
209 :attributes => { :type => 'array' },
209 :attributes => { :type => 'array' },
210 :child => {
210 :child => {
211 :tag => 'journal',
211 :tag => 'journal',
212 :attributes => { :id => '1'},
212 :attributes => { :id => '1'},
213 :child => {
213 :child => {
214 :tag => 'details',
214 :tag => 'details',
215 :attributes => { :type => 'array' },
215 :attributes => { :type => 'array' },
216 :child => {
216 :child => {
217 :tag => 'detail',
217 :tag => 'detail',
218 :attributes => { :name => 'status_id' },
218 :attributes => { :name => 'status_id' },
219 :child => {
219 :child => {
220 :tag => 'old_value',
220 :tag => 'old_value',
221 :content => '1',
221 :content => '1',
222 :sibling => {
222 :sibling => {
223 :tag => 'new_value',
223 :tag => 'new_value',
224 :content => '2'
224 :content => '2'
225 }
225 }
226 }
226 }
227 }
227 }
228 }
228 }
229 }
229 }
230 }
230 }
231 end
231 end
232 end
232 end
233 end
233 end
234
234
235 context "with custom fields" do
235 context "with custom fields" do
236 context ".xml" do
236 context ".xml" do
237 should "display custom fields" do
237 should "display custom fields" do
238 get '/issues/3.xml'
238 get '/issues/3.xml'
239
239
240 assert_tag :tag => 'issue',
240 assert_tag :tag => 'issue',
241 :child => {
241 :child => {
242 :tag => 'custom_fields',
242 :tag => 'custom_fields',
243 :attributes => { :type => 'array' },
243 :attributes => { :type => 'array' },
244 :child => {
244 :child => {
245 :tag => 'custom_field',
245 :tag => 'custom_field',
246 :attributes => { :id => '1'},
246 :attributes => { :id => '1'},
247 :child => {
247 :child => {
248 :tag => 'value',
248 :tag => 'value',
249 :content => 'MySQL'
249 :content => 'MySQL'
250 }
250 }
251 }
251 }
252 }
252 }
253
253
254 assert_nothing_raised do
254 assert_nothing_raised do
255 Hash.from_xml(response.body).to_xml
255 Hash.from_xml(response.body).to_xml
256 end
256 end
257 end
257 end
258 end
258 end
259 end
259 end
260
260
261 context "with multi custom fields" do
261 context "with multi custom fields" do
262 setup do
262 setup do
263 field = CustomField.find(1)
263 field = CustomField.find(1)
264 field.update_attribute :multiple, true
264 field.update_attribute :multiple, true
265 issue = Issue.find(3)
265 issue = Issue.find(3)
266 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
266 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
267 issue.save!
267 issue.save!
268 end
268 end
269
269
270 context ".xml" do
270 context ".xml" do
271 should "display custom fields" do
271 should "display custom fields" do
272 get '/issues/3.xml'
272 get '/issues/3.xml'
273 assert_response :success
273 assert_response :success
274 assert_tag :tag => 'issue',
274 assert_tag :tag => 'issue',
275 :child => {
275 :child => {
276 :tag => 'custom_fields',
276 :tag => 'custom_fields',
277 :attributes => { :type => 'array' },
277 :attributes => { :type => 'array' },
278 :child => {
278 :child => {
279 :tag => 'custom_field',
279 :tag => 'custom_field',
280 :attributes => { :id => '1'},
280 :attributes => { :id => '1'},
281 :child => {
281 :child => {
282 :tag => 'value',
282 :tag => 'value',
283 :attributes => { :type => 'array' },
283 :attributes => { :type => 'array' },
284 :children => { :count => 2 }
284 :children => { :count => 2 }
285 }
285 }
286 }
286 }
287 }
287 }
288
288
289 xml = Hash.from_xml(response.body)
289 xml = Hash.from_xml(response.body)
290 custom_fields = xml['issue']['custom_fields']
290 custom_fields = xml['issue']['custom_fields']
291 assert_kind_of Array, custom_fields
291 assert_kind_of Array, custom_fields
292 field = custom_fields.detect {|f| f['id'] == '1'}
292 field = custom_fields.detect {|f| f['id'] == '1'}
293 assert_kind_of Hash, field
293 assert_kind_of Hash, field
294 assert_equal ['MySQL', 'Oracle'], field['value'].sort
294 assert_equal ['MySQL', 'Oracle'], field['value'].sort
295 end
295 end
296 end
296 end
297
297
298 context ".json" do
298 context ".json" do
299 should "display custom fields" do
299 should "display custom fields" do
300 get '/issues/3.json'
300 get '/issues/3.json'
301 assert_response :success
301 assert_response :success
302 json = ActiveSupport::JSON.decode(response.body)
302 json = ActiveSupport::JSON.decode(response.body)
303 custom_fields = json['issue']['custom_fields']
303 custom_fields = json['issue']['custom_fields']
304 assert_kind_of Array, custom_fields
304 assert_kind_of Array, custom_fields
305 field = custom_fields.detect {|f| f['id'] == 1}
305 field = custom_fields.detect {|f| f['id'] == 1}
306 assert_kind_of Hash, field
306 assert_kind_of Hash, field
307 assert_equal ['MySQL', 'Oracle'], field['value'].sort
307 assert_equal ['MySQL', 'Oracle'], field['value'].sort
308 end
308 end
309 end
309 end
310 end
310 end
311
311
312 context "with empty value for multi custom field" do
312 context "with empty value for multi custom field" do
313 setup do
313 setup do
314 field = CustomField.find(1)
314 field = CustomField.find(1)
315 field.update_attribute :multiple, true
315 field.update_attribute :multiple, true
316 issue = Issue.find(3)
316 issue = Issue.find(3)
317 issue.custom_field_values = {1 => ['']}
317 issue.custom_field_values = {1 => ['']}
318 issue.save!
318 issue.save!
319 end
319 end
320
320
321 context ".xml" do
321 context ".xml" do
322 should "display custom fields" do
322 should "display custom fields" do
323 get '/issues/3.xml'
323 get '/issues/3.xml'
324 assert_response :success
324 assert_response :success
325 assert_tag :tag => 'issue',
325 assert_tag :tag => 'issue',
326 :child => {
326 :child => {
327 :tag => 'custom_fields',
327 :tag => 'custom_fields',
328 :attributes => { :type => 'array' },
328 :attributes => { :type => 'array' },
329 :child => {
329 :child => {
330 :tag => 'custom_field',
330 :tag => 'custom_field',
331 :attributes => { :id => '1'},
331 :attributes => { :id => '1'},
332 :child => {
332 :child => {
333 :tag => 'value',
333 :tag => 'value',
334 :attributes => { :type => 'array' },
334 :attributes => { :type => 'array' },
335 :children => { :count => 0 }
335 :children => { :count => 0 }
336 }
336 }
337 }
337 }
338 }
338 }
339
339
340 xml = Hash.from_xml(response.body)
340 xml = Hash.from_xml(response.body)
341 custom_fields = xml['issue']['custom_fields']
341 custom_fields = xml['issue']['custom_fields']
342 assert_kind_of Array, custom_fields
342 assert_kind_of Array, custom_fields
343 field = custom_fields.detect {|f| f['id'] == '1'}
343 field = custom_fields.detect {|f| f['id'] == '1'}
344 assert_kind_of Hash, field
344 assert_kind_of Hash, field
345 assert_equal [], field['value']
345 assert_equal [], field['value']
346 end
346 end
347 end
347 end
348
348
349 context ".json" do
349 context ".json" do
350 should "display custom fields" do
350 should "display custom fields" do
351 get '/issues/3.json'
351 get '/issues/3.json'
352 assert_response :success
352 assert_response :success
353 json = ActiveSupport::JSON.decode(response.body)
353 json = ActiveSupport::JSON.decode(response.body)
354 custom_fields = json['issue']['custom_fields']
354 custom_fields = json['issue']['custom_fields']
355 assert_kind_of Array, custom_fields
355 assert_kind_of Array, custom_fields
356 field = custom_fields.detect {|f| f['id'] == 1}
356 field = custom_fields.detect {|f| f['id'] == 1}
357 assert_kind_of Hash, field
357 assert_kind_of Hash, field
358 assert_equal [], field['value'].sort
358 assert_equal [], field['value'].sort
359 end
359 end
360 end
360 end
361 end
361 end
362
362
363 context "with attachments" do
363 context "with attachments" do
364 context ".xml" do
364 context ".xml" do
365 should "display attachments" do
365 should "display attachments" do
366 get '/issues/3.xml?include=attachments'
366 get '/issues/3.xml?include=attachments'
367
367
368 assert_tag :tag => 'issue',
368 assert_tag :tag => 'issue',
369 :child => {
369 :child => {
370 :tag => 'attachments',
370 :tag => 'attachments',
371 :children => {:count => 5},
371 :children => {:count => 5},
372 :child => {
372 :child => {
373 :tag => 'attachment',
373 :tag => 'attachment',
374 :child => {
374 :child => {
375 :tag => 'filename',
375 :tag => 'filename',
376 :content => 'source.rb',
376 :content => 'source.rb',
377 :sibling => {
377 :sibling => {
378 :tag => 'content_url',
378 :tag => 'content_url',
379 :content => 'http://www.example.com/attachments/download/4/source.rb'
379 :content => 'http://www.example.com/attachments/download/4/source.rb'
380 }
380 }
381 }
381 }
382 }
382 }
383 }
383 }
384 end
384 end
385 end
385 end
386 end
386 end
387
387
388 context "with subtasks" do
388 context "with subtasks" do
389 setup do
389 setup do
390 @c1 = Issue.create!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
390 @c1 = Issue.create!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
391 @c2 = Issue.create!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
391 @c2 = Issue.create!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
392 @c3 = Issue.create!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => @c1.id)
392 @c3 = Issue.create!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => @c1.id)
393 end
393 end
394
394
395 context ".xml" do
395 context ".xml" do
396 should "display children" do
396 should "display children" do
397 get '/issues/1.xml?include=children'
397 get '/issues/1.xml?include=children'
398
398
399 assert_tag :tag => 'issue',
399 assert_tag :tag => 'issue',
400 :child => {
400 :child => {
401 :tag => 'children',
401 :tag => 'children',
402 :children => {:count => 2},
402 :children => {:count => 2},
403 :child => {
403 :child => {
404 :tag => 'issue',
404 :tag => 'issue',
405 :attributes => {:id => @c1.id.to_s},
405 :attributes => {:id => @c1.id.to_s},
406 :child => {
406 :child => {
407 :tag => 'subject',
407 :tag => 'subject',
408 :content => 'child c1',
408 :content => 'child c1',
409 :sibling => {
409 :sibling => {
410 :tag => 'children',
410 :tag => 'children',
411 :children => {:count => 1},
411 :children => {:count => 1},
412 :child => {
412 :child => {
413 :tag => 'issue',
413 :tag => 'issue',
414 :attributes => {:id => @c3.id.to_s}
414 :attributes => {:id => @c3.id.to_s}
415 }
415 }
416 }
416 }
417 }
417 }
418 }
418 }
419 }
419 }
420 end
420 end
421
421
422 context ".json" do
422 context ".json" do
423 should "display children" do
423 should "display children" do
424 get '/issues/1.json?include=children'
424 get '/issues/1.json?include=children'
425
425
426 json = ActiveSupport::JSON.decode(response.body)
426 json = ActiveSupport::JSON.decode(response.body)
427 assert_equal([
427 assert_equal([
428 {
428 {
429 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
429 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
430 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
430 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
431 },
431 },
432 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
432 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
433 ],
433 ],
434 json['issue']['children'])
434 json['issue']['children'])
435 end
435 end
436 end
436 end
437 end
437 end
438 end
438 end
439 end
439 end
440
440
441 context "POST /issues.xml" do
441 context "POST /issues.xml" do
442 should_allow_api_authentication(:post,
442 should_allow_api_authentication(:post,
443 '/issues.xml',
443 '/issues.xml',
444 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
444 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
445 {:success_code => :created})
445 {:success_code => :created})
446
446
447 should "create an issue with the attributes" do
447 should "create an issue with the attributes" do
448 assert_difference('Issue.count') do
448 assert_difference('Issue.count') do
449 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
449 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
450 end
450 end
451
451
452 issue = Issue.first(:order => 'id DESC')
452 issue = Issue.first(:order => 'id DESC')
453 assert_equal 1, issue.project_id
453 assert_equal 1, issue.project_id
454 assert_equal 2, issue.tracker_id
454 assert_equal 2, issue.tracker_id
455 assert_equal 3, issue.status_id
455 assert_equal 3, issue.status_id
456 assert_equal 'API test', issue.subject
456 assert_equal 'API test', issue.subject
457
457
458 assert_response :created
458 assert_response :created
459 assert_equal 'application/xml', @response.content_type
459 assert_equal 'application/xml', @response.content_type
460 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
460 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
461 end
461 end
462 end
462 end
463
463
464 context "POST /issues.xml with failure" do
464 context "POST /issues.xml with failure" do
465 should "have an errors tag" do
465 should "have an errors tag" do
466 assert_no_difference('Issue.count') do
466 assert_no_difference('Issue.count') do
467 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
467 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
468 end
468 end
469
469
470 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
470 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
471 end
471 end
472 end
472 end
473
473
474 context "POST /issues.json" do
474 context "POST /issues.json" do
475 should_allow_api_authentication(:post,
475 should_allow_api_authentication(:post,
476 '/issues.json',
476 '/issues.json',
477 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
477 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
478 {:success_code => :created})
478 {:success_code => :created})
479
479
480 should "create an issue with the attributes" do
480 should "create an issue with the attributes" do
481 assert_difference('Issue.count') do
481 assert_difference('Issue.count') do
482 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
482 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
483 end
483 end
484
484
485 issue = Issue.first(:order => 'id DESC')
485 issue = Issue.first(:order => 'id DESC')
486 assert_equal 1, issue.project_id
486 assert_equal 1, issue.project_id
487 assert_equal 2, issue.tracker_id
487 assert_equal 2, issue.tracker_id
488 assert_equal 3, issue.status_id
488 assert_equal 3, issue.status_id
489 assert_equal 'API test', issue.subject
489 assert_equal 'API test', issue.subject
490 end
490 end
491
491
492 end
492 end
493
493
494 context "POST /issues.json with failure" do
494 context "POST /issues.json with failure" do
495 should "have an errors element" do
495 should "have an errors element" do
496 assert_no_difference('Issue.count') do
496 assert_no_difference('Issue.count') do
497 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
497 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
498 end
498 end
499
499
500 json = ActiveSupport::JSON.decode(response.body)
500 json = ActiveSupport::JSON.decode(response.body)
501 assert json['errors'].include?("Subject can't be blank")
501 assert json['errors'].include?("Subject can't be blank")
502 end
502 end
503 end
503 end
504
504
505 # Issue 6 is on a private project
505 # Issue 6 is on a private project
506 context "PUT /issues/6.xml" do
506 context "PUT /issues/6.xml" do
507 setup do
507 setup do
508 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
508 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
509 end
509 end
510
510
511 should_allow_api_authentication(:put,
511 should_allow_api_authentication(:put,
512 '/issues/6.xml',
512 '/issues/6.xml',
513 {:issue => {:subject => 'API update', :notes => 'A new note'}},
513 {:issue => {:subject => 'API update', :notes => 'A new note'}},
514 {:success_code => :ok})
514 {:success_code => :ok})
515
515
516 should "not create a new issue" do
516 should "not create a new issue" do
517 assert_no_difference('Issue.count') do
517 assert_no_difference('Issue.count') do
518 put '/issues/6.xml', @parameters, credentials('jsmith')
518 put '/issues/6.xml', @parameters, credentials('jsmith')
519 end
519 end
520 end
520 end
521
521
522 should "create a new journal" do
522 should "create a new journal" do
523 assert_difference('Journal.count') do
523 assert_difference('Journal.count') do
524 put '/issues/6.xml', @parameters, credentials('jsmith')
524 put '/issues/6.xml', @parameters, credentials('jsmith')
525 end
525 end
526 end
526 end
527
527
528 should "add the note to the journal" do
528 should "add the note to the journal" do
529 put '/issues/6.xml', @parameters, credentials('jsmith')
529 put '/issues/6.xml', @parameters, credentials('jsmith')
530
530
531 journal = Journal.last
531 journal = Journal.last
532 assert_equal "A new note", journal.notes
532 assert_equal "A new note", journal.notes
533 end
533 end
534
534
535 should "update the issue" do
535 should "update the issue" do
536 put '/issues/6.xml', @parameters, credentials('jsmith')
536 put '/issues/6.xml', @parameters, credentials('jsmith')
537
537
538 issue = Issue.find(6)
538 issue = Issue.find(6)
539 assert_equal "API update", issue.subject
539 assert_equal "API update", issue.subject
540 end
540 end
541
541
542 end
542 end
543
543
544 context "PUT /issues/3.xml with custom fields" do
544 context "PUT /issues/3.xml with custom fields" do
545 setup do
545 setup do
546 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
546 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
547 end
547 end
548
548
549 should "update custom fields" do
549 should "update custom fields" do
550 assert_no_difference('Issue.count') do
550 assert_no_difference('Issue.count') do
551 put '/issues/3.xml', @parameters, credentials('jsmith')
551 put '/issues/3.xml', @parameters, credentials('jsmith')
552 end
552 end
553
553
554 issue = Issue.find(3)
554 issue = Issue.find(3)
555 assert_equal '150', issue.custom_value_for(2).value
555 assert_equal '150', issue.custom_value_for(2).value
556 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
556 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
557 end
557 end
558 end
558 end
559
559
560 context "PUT /issues/3.xml with multi custom fields" do
560 context "PUT /issues/3.xml with multi custom fields" do
561 setup do
561 setup do
562 field = CustomField.find(1)
562 field = CustomField.find(1)
563 field.update_attribute :multiple, true
563 field.update_attribute :multiple, true
564 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] }, {'id' => '2', 'value' => '150'}]}}
564 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] }, {'id' => '2', 'value' => '150'}]}}
565 end
565 end
566
566
567 should "update custom fields" do
567 should "update custom fields" do
568 assert_no_difference('Issue.count') do
568 assert_no_difference('Issue.count') do
569 put '/issues/3.xml', @parameters, credentials('jsmith')
569 put '/issues/3.xml', @parameters, credentials('jsmith')
570 end
570 end
571
571
572 issue = Issue.find(3)
572 issue = Issue.find(3)
573 assert_equal '150', issue.custom_value_for(2).value
573 assert_equal '150', issue.custom_value_for(2).value
574 assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort
574 assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort
575 end
575 end
576 end
576 end
577
577
578 context "PUT /issues/3.xml with project change" do
578 context "PUT /issues/3.xml with project change" do
579 setup do
579 setup do
580 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
580 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
581 end
581 end
582
582
583 should "update project" do
583 should "update project" do
584 assert_no_difference('Issue.count') do
584 assert_no_difference('Issue.count') do
585 put '/issues/3.xml', @parameters, credentials('jsmith')
585 put '/issues/3.xml', @parameters, credentials('jsmith')
586 end
586 end
587
587
588 issue = Issue.find(3)
588 issue = Issue.find(3)
589 assert_equal 2, issue.project_id
589 assert_equal 2, issue.project_id
590 assert_equal 'Project changed', issue.subject
590 assert_equal 'Project changed', issue.subject
591 end
591 end
592 end
592 end
593
593
594 context "PUT /issues/6.xml with failed update" do
594 context "PUT /issues/6.xml with failed update" do
595 setup do
595 setup do
596 @parameters = {:issue => {:subject => ''}}
596 @parameters = {:issue => {:subject => ''}}
597 end
597 end
598
598
599 should "not create a new issue" do
599 should "not create a new issue" do
600 assert_no_difference('Issue.count') do
600 assert_no_difference('Issue.count') do
601 put '/issues/6.xml', @parameters, credentials('jsmith')
601 put '/issues/6.xml', @parameters, credentials('jsmith')
602 end
602 end
603 end
603 end
604
604
605 should "not create a new journal" do
605 should "not create a new journal" do
606 assert_no_difference('Journal.count') do
606 assert_no_difference('Journal.count') do
607 put '/issues/6.xml', @parameters, credentials('jsmith')
607 put '/issues/6.xml', @parameters, credentials('jsmith')
608 end
608 end
609 end
609 end
610
610
611 should "have an errors tag" do
611 should "have an errors tag" do
612 put '/issues/6.xml', @parameters, credentials('jsmith')
612 put '/issues/6.xml', @parameters, credentials('jsmith')
613
613
614 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
614 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
615 end
615 end
616 end
616 end
617
617
618 context "PUT /issues/6.json" do
618 context "PUT /issues/6.json" do
619 setup do
619 setup do
620 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
620 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
621 end
621 end
622
622
623 should_allow_api_authentication(:put,
623 should_allow_api_authentication(:put,
624 '/issues/6.json',
624 '/issues/6.json',
625 {:issue => {:subject => 'API update', :notes => 'A new note'}},
625 {:issue => {:subject => 'API update', :notes => 'A new note'}},
626 {:success_code => :ok})
626 {:success_code => :ok})
627
627
628 should "not create a new issue" do
628 should "update the issue" do
629 assert_no_difference('Issue.count') do
629 assert_no_difference('Issue.count') do
630 put '/issues/6.json', @parameters, credentials('jsmith')
630 assert_difference('Journal.count') do
631 end
631 put '/issues/6.json', @parameters, credentials('jsmith')
632 end
633
632
634 should "create a new journal" do
633 assert_response :ok
635 assert_difference('Journal.count') do
634 assert_equal '', response.body
636 put '/issues/6.json', @parameters, credentials('jsmith')
635 end
637 end
636 end
638 end
639
640 should "add the note to the journal" do
641 put '/issues/6.json', @parameters, credentials('jsmith')
642
643 journal = Journal.last
644 assert_equal "A new note", journal.notes
645 end
646
647 should "update the issue" do
648 put '/issues/6.json', @parameters, credentials('jsmith')
649
637
650 issue = Issue.find(6)
638 issue = Issue.find(6)
651 assert_equal "API update", issue.subject
639 assert_equal "API update", issue.subject
640 journal = Journal.last
641 assert_equal "A new note", journal.notes
652 end
642 end
653
654 end
643 end
655
644
656 context "PUT /issues/6.json with failed update" do
645 context "PUT /issues/6.json with failed update" do
657 setup do
646 should "return errors" do
658 @parameters = {:issue => {:subject => ''}}
659 end
660
661 should "not create a new issue" do
662 assert_no_difference('Issue.count') do
647 assert_no_difference('Issue.count') do
663 put '/issues/6.json', @parameters, credentials('jsmith')
648 assert_no_difference('Journal.count') do
664 end
649 put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith')
665 end
666
650
667 should "not create a new journal" do
651 assert_response :unprocessable_entity
668 assert_no_difference('Journal.count') do
652 end
669 put '/issues/6.json', @parameters, credentials('jsmith')
670 end
653 end
671 end
672
673 should "have an errors attribute" do
674 put '/issues/6.json', @parameters, credentials('jsmith')
675
654
676 json = ActiveSupport::JSON.decode(response.body)
655 json = ActiveSupport::JSON.decode(response.body)
677 assert json['errors'].include?("Subject can't be blank")
656 assert json['errors'].include?("Subject can't be blank")
678 end
657 end
679 end
658 end
680
659
681 context "DELETE /issues/1.xml" do
660 context "DELETE /issues/1.xml" do
682 should_allow_api_authentication(:delete,
661 should_allow_api_authentication(:delete,
683 '/issues/6.xml',
662 '/issues/6.xml',
684 {},
663 {},
685 {:success_code => :ok})
664 {:success_code => :ok})
686
665
687 should "delete the issue" do
666 should "delete the issue" do
688 assert_difference('Issue.count',-1) do
667 assert_difference('Issue.count', -1) do
689 delete '/issues/6.xml', {}, credentials('jsmith')
668 delete '/issues/6.xml', {}, credentials('jsmith')
669
670 assert_response :ok
671 assert_equal '', response.body
690 end
672 end
691
673
692 assert_nil Issue.find_by_id(6)
674 assert_nil Issue.find_by_id(6)
693 end
675 end
694 end
676 end
695
677
696 context "DELETE /issues/1.json" do
678 context "DELETE /issues/1.json" do
697 should_allow_api_authentication(:delete,
679 should_allow_api_authentication(:delete,
698 '/issues/6.json',
680 '/issues/6.json',
699 {},
681 {},
700 {:success_code => :ok})
682 {:success_code => :ok})
701
683
702 should "delete the issue" do
684 should "delete the issue" do
703 assert_difference('Issue.count',-1) do
685 assert_difference('Issue.count', -1) do
704 delete '/issues/6.json', {}, credentials('jsmith')
686 delete '/issues/6.json', {}, credentials('jsmith')
687
688 assert_response :ok
689 assert_equal '', response.body
705 end
690 end
706
691
707 assert_nil Issue.find_by_id(6)
692 assert_nil Issue.find_by_id(6)
708 end
693 end
709 end
694 end
710
695
711 def test_create_issue_with_uploaded_file
696 def test_create_issue_with_uploaded_file
712 set_tmp_attachments_directory
697 set_tmp_attachments_directory
713
698
714 # upload the file
699 # upload the file
715 assert_difference 'Attachment.count' do
700 assert_difference 'Attachment.count' do
716 post '/uploads.xml', 'test_create_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
701 post '/uploads.xml', 'test_create_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
717 assert_response :created
702 assert_response :created
718 end
703 end
719 xml = Hash.from_xml(response.body)
704 xml = Hash.from_xml(response.body)
720 token = xml['upload']['token']
705 token = xml['upload']['token']
721 attachment = Attachment.first(:order => 'id DESC')
706 attachment = Attachment.first(:order => 'id DESC')
722
707
723 # create the issue with the upload's token
708 # create the issue with the upload's token
724 assert_difference 'Issue.count' do
709 assert_difference 'Issue.count' do
725 post '/issues.xml',
710 post '/issues.xml',
726 {:issue => {:project_id => 1, :subject => 'Uploaded file', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
711 {:issue => {:project_id => 1, :subject => 'Uploaded file', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
727 credentials('jsmith')
712 credentials('jsmith')
728 assert_response :created
713 assert_response :created
729 end
714 end
730 issue = Issue.first(:order => 'id DESC')
715 issue = Issue.first(:order => 'id DESC')
731 assert_equal 1, issue.attachments.count
716 assert_equal 1, issue.attachments.count
732 assert_equal attachment, issue.attachments.first
717 assert_equal attachment, issue.attachments.first
733
718
734 attachment.reload
719 attachment.reload
735 assert_equal 'test.txt', attachment.filename
720 assert_equal 'test.txt', attachment.filename
736 assert_equal 'text/plain', attachment.content_type
721 assert_equal 'text/plain', attachment.content_type
737 assert_equal 'test_create_with_upload'.size, attachment.filesize
722 assert_equal 'test_create_with_upload'.size, attachment.filesize
738 assert_equal 2, attachment.author_id
723 assert_equal 2, attachment.author_id
739
724
740 # get the issue with its attachments
725 # get the issue with its attachments
741 get "/issues/#{issue.id}.xml", :include => 'attachments'
726 get "/issues/#{issue.id}.xml", :include => 'attachments'
742 assert_response :success
727 assert_response :success
743 xml = Hash.from_xml(response.body)
728 xml = Hash.from_xml(response.body)
744 attachments = xml['issue']['attachments']
729 attachments = xml['issue']['attachments']
745 assert_kind_of Array, attachments
730 assert_kind_of Array, attachments
746 assert_equal 1, attachments.size
731 assert_equal 1, attachments.size
747 url = attachments.first['content_url']
732 url = attachments.first['content_url']
748 assert_not_nil url
733 assert_not_nil url
749
734
750 # download the attachment
735 # download the attachment
751 get url
736 get url
752 assert_response :success
737 assert_response :success
753 end
738 end
754
739
755 def test_update_issue_with_uploaded_file
740 def test_update_issue_with_uploaded_file
756 set_tmp_attachments_directory
741 set_tmp_attachments_directory
757
742
758 # upload the file
743 # upload the file
759 assert_difference 'Attachment.count' do
744 assert_difference 'Attachment.count' do
760 post '/uploads.xml', 'test_upload_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
745 post '/uploads.xml', 'test_upload_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
761 assert_response :created
746 assert_response :created
762 end
747 end
763 xml = Hash.from_xml(response.body)
748 xml = Hash.from_xml(response.body)
764 token = xml['upload']['token']
749 token = xml['upload']['token']
765 attachment = Attachment.first(:order => 'id DESC')
750 attachment = Attachment.first(:order => 'id DESC')
766
751
767 # update the issue with the upload's token
752 # update the issue with the upload's token
768 assert_difference 'Journal.count' do
753 assert_difference 'Journal.count' do
769 put '/issues/1.xml',
754 put '/issues/1.xml',
770 {:issue => {:notes => 'Attachment added', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
755 {:issue => {:notes => 'Attachment added', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
771 credentials('jsmith')
756 credentials('jsmith')
772 assert_response :ok
757 assert_response :ok
773 assert_equal '', @response.body
758 assert_equal '', @response.body
774 end
759 end
775
760
776 issue = Issue.find(1)
761 issue = Issue.find(1)
777 assert_include attachment, issue.attachments
762 assert_include attachment, issue.attachments
778 end
763 end
779 end
764 end
General Comments 0
You need to be logged in to leave comments. Login now