annotate test/integration/api_test/.svn/text-base/issues_test.rb.svn-base @ 853:969bb872d4bf feature_142

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