comparison .svn/pristine/2b/2b0a9f999f6063790f2925cfcbf5bec32cb0108e.svn-base @ 909:cbb26bc654de redmine-1.3

Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author Chris Cannam
date Fri, 24 Feb 2012 19:09:32 +0000
parents
children
comparison
equal deleted inserted replaced
908:c6c2cbd0afee 909:cbb26bc654de
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 require File.expand_path('../../../test_helper', __FILE__)
19
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 fixtures :projects,
22 :users,
23 :roles,
24 :members,
25 :member_roles,
26 :issues,
27 :issue_statuses,
28 :versions,
29 :trackers,
30 :projects_trackers,
31 :issue_categories,
32 :enabled_modules,
33 :enumerations,
34 :attachments,
35 :workflows,
36 :custom_fields,
37 :custom_values,
38 :custom_fields_projects,
39 :custom_fields_trackers,
40 :time_entries,
41 :journals,
42 :journal_details,
43 :queries,
44 :attachments
45
46 def setup
47 Setting.rest_api_enabled = '1'
48 end
49
50 context "/issues" do
51 # Use a private project to make sure auth is really working and not just
52 # only showing public issues.
53 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
54
55 should "contain metadata" do
56 get '/issues.xml'
57
58 assert_tag :tag => 'issues',
59 :attributes => {
60 :type => 'array',
61 :total_count => assigns(:issue_count),
62 :limit => 25,
63 :offset => 0
64 }
65 end
66
67 context "with offset and limit" do
68 should "use the params" do
69 get '/issues.xml?offset=2&limit=3'
70
71 assert_equal 3, assigns(:limit)
72 assert_equal 2, assigns(:offset)
73 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
74 end
75 end
76
77 context "with nometa param" do
78 should "not contain metadata" do
79 get '/issues.xml?nometa=1'
80
81 assert_tag :tag => 'issues',
82 :attributes => {
83 :type => 'array',
84 :total_count => nil,
85 :limit => nil,
86 :offset => nil
87 }
88 end
89 end
90
91 context "with nometa header" do
92 should "not contain metadata" do
93 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
94
95 assert_tag :tag => 'issues',
96 :attributes => {
97 :type => 'array',
98 :total_count => nil,
99 :limit => nil,
100 :offset => nil
101 }
102 end
103 end
104
105 context "with relations" do
106 should "display relations" do
107 get '/issues.xml?include=relations'
108
109 assert_response :success
110 assert_equal 'application/xml', @response.content_type
111 assert_tag 'relations',
112 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
113 :children => {:count => 1},
114 :child => {
115 :tag => 'relation',
116 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
117 }
118 assert_tag 'relations',
119 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
120 :children => {:count => 0}
121 end
122 end
123
124 context "with invalid query params" do
125 should "return errors" do
126 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
127
128 assert_response :unprocessable_entity
129 assert_equal 'application/xml', @response.content_type
130 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
131 end
132 end
133
134 context "with custom field filter" 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']}}
137
138 expected_ids = Issue.visible.all(
139 :include => :custom_values,
140 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
141
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) }
144 end
145 end
146 end
147
148 context "with custom field filter (shorthand method)" do
149 should "show only issues with the custom field value" do
150 get '/issues.xml', { :cf_1 => 'MySQL' }
151
152 expected_ids = Issue.visible.all(
153 :include => :custom_values,
154 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
155
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) }
158 end
159 end
160 end
161 end
162
163 context "/index.json" do
164 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
165 end
166
167 context "/index.xml with filter" do
168 should "show only issues with the status_id" do
169 get '/issues.xml?status_id=5'
170
171 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
172
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) }
175 end
176 end
177 end
178
179 context "/index.json with filter" do
180 should "show only issues with the status_id" do
181 get '/issues.json?status_id=5'
182
183 json = ActiveSupport::JSON.decode(response.body)
184 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
185 assert_equal 3, status_ids_used.length
186 assert status_ids_used.all? {|id| id == 5 }
187 end
188
189 end
190
191 # Issue 6 is on a private project
192 context "/issues/6.xml" do
193 should_allow_api_authentication(:get, "/issues/6.xml")
194 end
195
196 context "/issues/6.json" do
197 should_allow_api_authentication(:get, "/issues/6.json")
198 end
199
200 context "GET /issues/:id" do
201 context "with journals" do
202 context ".xml" do
203 should "display journals" do
204 get '/issues/1.xml?include=journals'
205
206 assert_tag :tag => 'issue',
207 :child => {
208 :tag => 'journals',
209 :attributes => { :type => 'array' },
210 :child => {
211 :tag => 'journal',
212 :attributes => { :id => '1'},
213 :child => {
214 :tag => 'details',
215 :attributes => { :type => 'array' },
216 :child => {
217 :tag => 'detail',
218 :attributes => { :name => 'status_id' },
219 :child => {
220 :tag => 'old_value',
221 :content => '1',
222 :sibling => {
223 :tag => 'new_value',
224 :content => '2'
225 }
226 }
227 }
228 }
229 }
230 }
231 end
232 end
233 end
234
235 context "with custom fields" do
236 context ".xml" do
237 should "display custom fields" do
238 get '/issues/3.xml'
239
240 assert_tag :tag => 'issue',
241 :child => {
242 :tag => 'custom_fields',
243 :attributes => { :type => 'array' },
244 :child => {
245 :tag => 'custom_field',
246 :attributes => { :id => '1'},
247 :child => {
248 :tag => 'value',
249 :content => 'MySQL'
250 }
251 }
252 }
253
254 assert_nothing_raised do
255 Hash.from_xml(response.body).to_xml
256 end
257 end
258 end
259 end
260
261 context "with attachments" do
262 context ".xml" do
263 should "display attachments" do
264 get '/issues/3.xml?include=attachments'
265
266 assert_tag :tag => 'issue',
267 :child => {
268 :tag => 'attachments',
269 :children => {:count => 5},
270 :child => {
271 :tag => 'attachment',
272 :child => {
273 :tag => 'filename',
274 :content => 'source.rb',
275 :sibling => {
276 :tag => 'content_url',
277 :content => 'http://www.example.com/attachments/download/4/source.rb'
278 }
279 }
280 }
281 }
282 end
283 end
284 end
285
286 context "with subtasks" do
287 setup do
288 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
289 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
290 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
291 end
292
293 context ".xml" do
294 should "display children" do
295 get '/issues/1.xml?include=children'
296
297 assert_tag :tag => 'issue',
298 :child => {
299 :tag => 'children',
300 :children => {:count => 2},
301 :child => {
302 :tag => 'issue',
303 :attributes => {:id => @c1.id.to_s},
304 :child => {
305 :tag => 'subject',
306 :content => 'child c1',
307 :sibling => {
308 :tag => 'children',
309 :children => {:count => 1},
310 :child => {
311 :tag => 'issue',
312 :attributes => {:id => @c3.id.to_s}
313 }
314 }
315 }
316 }
317 }
318 end
319
320 context ".json" do
321 should "display children" do
322 get '/issues/1.json?include=children'
323
324 json = ActiveSupport::JSON.decode(response.body)
325 assert_equal([
326 {
327 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
328 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
329 },
330 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
331 ],
332 json['issue']['children'])
333 end
334 end
335 end
336 end
337 end
338
339 context "POST /issues.xml" do
340 should_allow_api_authentication(:post,
341 '/issues.xml',
342 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
343 {:success_code => :created})
344
345 should "create an issue with the attributes" do
346 assert_difference('Issue.count') do
347 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
348 end
349
350 issue = Issue.first(:order => 'id DESC')
351 assert_equal 1, issue.project_id
352 assert_equal 2, issue.tracker_id
353 assert_equal 3, issue.status_id
354 assert_equal 'API test', issue.subject
355
356 assert_response :created
357 assert_equal 'application/xml', @response.content_type
358 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
359 end
360 end
361
362 context "POST /issues.xml with failure" do
363 should "have an errors tag" do
364 assert_no_difference('Issue.count') do
365 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
366 end
367
368 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
369 end
370 end
371
372 context "POST /issues.json" do
373 should_allow_api_authentication(:post,
374 '/issues.json',
375 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
376 {:success_code => :created})
377
378 should "create an issue with the attributes" do
379 assert_difference('Issue.count') do
380 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
381 end
382
383 issue = Issue.first(:order => 'id DESC')
384 assert_equal 1, issue.project_id
385 assert_equal 2, issue.tracker_id
386 assert_equal 3, issue.status_id
387 assert_equal 'API test', issue.subject
388 end
389
390 end
391
392 context "POST /issues.json with failure" do
393 should "have an errors element" do
394 assert_no_difference('Issue.count') do
395 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
396 end
397
398 json = ActiveSupport::JSON.decode(response.body)
399 assert json['errors'].include?(['subject', "can't be blank"])
400 end
401 end
402
403 # Issue 6 is on a private project
404 context "PUT /issues/6.xml" do
405 setup do
406 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
407 @headers = { :authorization => credentials('jsmith') }
408 end
409
410 should_allow_api_authentication(:put,
411 '/issues/6.xml',
412 {:issue => {:subject => 'API update', :notes => 'A new note'}},
413 {:success_code => :ok})
414
415 should "not create a new issue" do
416 assert_no_difference('Issue.count') do
417 put '/issues/6.xml', @parameters, @headers
418 end
419 end
420
421 should "create a new journal" do
422 assert_difference('Journal.count') do
423 put '/issues/6.xml', @parameters, @headers
424 end
425 end
426
427 should "add the note to the journal" do
428 put '/issues/6.xml', @parameters, @headers
429
430 journal = Journal.last
431 assert_equal "A new note", journal.notes
432 end
433
434 should "update the issue" do
435 put '/issues/6.xml', @parameters, @headers
436
437 issue = Issue.find(6)
438 assert_equal "API update", issue.subject
439 end
440
441 end
442
443 context "PUT /issues/3.xml with custom fields" do
444 setup do
445 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
446 @headers = { :authorization => credentials('jsmith') }
447 end
448
449 should "update custom fields" do
450 assert_no_difference('Issue.count') do
451 put '/issues/3.xml', @parameters, @headers
452 end
453
454 issue = Issue.find(3)
455 assert_equal '150', issue.custom_value_for(2).value
456 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
457 end
458 end
459
460 context "PUT /issues/6.xml with failed update" do
461 setup do
462 @parameters = {:issue => {:subject => ''}}
463 @headers = { :authorization => credentials('jsmith') }
464 end
465
466 should "not create a new issue" do
467 assert_no_difference('Issue.count') do
468 put '/issues/6.xml', @parameters, @headers
469 end
470 end
471
472 should "not create a new journal" do
473 assert_no_difference('Journal.count') do
474 put '/issues/6.xml', @parameters, @headers
475 end
476 end
477
478 should "have an errors tag" do
479 put '/issues/6.xml', @parameters, @headers
480
481 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
482 end
483 end
484
485 context "PUT /issues/6.json" do
486 setup do
487 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
488 @headers = { :authorization => credentials('jsmith') }
489 end
490
491 should_allow_api_authentication(:put,
492 '/issues/6.json',
493 {:issue => {:subject => 'API update', :notes => 'A new note'}},
494 {:success_code => :ok})
495
496 should "not create a new issue" do
497 assert_no_difference('Issue.count') do
498 put '/issues/6.json', @parameters, @headers
499 end
500 end
501
502 should "create a new journal" do
503 assert_difference('Journal.count') do
504 put '/issues/6.json', @parameters, @headers
505 end
506 end
507
508 should "add the note to the journal" do
509 put '/issues/6.json', @parameters, @headers
510
511 journal = Journal.last
512 assert_equal "A new note", journal.notes
513 end
514
515 should "update the issue" do
516 put '/issues/6.json', @parameters, @headers
517
518 issue = Issue.find(6)
519 assert_equal "API update", issue.subject
520 end
521
522 end
523
524 context "PUT /issues/6.json with failed update" do
525 setup do
526 @parameters = {:issue => {:subject => ''}}
527 @headers = { :authorization => credentials('jsmith') }
528 end
529
530 should "not create a new issue" do
531 assert_no_difference('Issue.count') do
532 put '/issues/6.json', @parameters, @headers
533 end
534 end
535
536 should "not create a new journal" do
537 assert_no_difference('Journal.count') do
538 put '/issues/6.json', @parameters, @headers
539 end
540 end
541
542 should "have an errors attribute" do
543 put '/issues/6.json', @parameters, @headers
544
545 json = ActiveSupport::JSON.decode(response.body)
546 assert json['errors'].include?(['subject', "can't be blank"])
547 end
548 end
549
550 context "DELETE /issues/1.xml" do
551 should_allow_api_authentication(:delete,
552 '/issues/6.xml',
553 {},
554 {:success_code => :ok})
555
556 should "delete the issue" do
557 assert_difference('Issue.count',-1) do
558 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
559 end
560
561 assert_nil Issue.find_by_id(6)
562 end
563 end
564
565 context "DELETE /issues/1.json" do
566 should_allow_api_authentication(:delete,
567 '/issues/6.json',
568 {},
569 {:success_code => :ok})
570
571 should "delete the issue" do
572 assert_difference('Issue.count',-1) do
573 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
574 end
575
576 assert_nil Issue.find_by_id(6)
577 end
578 end
579
580 def credentials(user, password=nil)
581 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
582 end
583 end