issues_controller_test.rb 57.4 KB
Newer Older
1
# Redmine - project management software
2
# Copyright (C) 2006-2011  Jean-Philippe Lang
3 4 5 6 7
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
8
#
9 10 11 12
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
13
#
14 15 16 17
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

18
require File.expand_path('../../test_helper', __FILE__)
19 20
require 'issues_controller'

edavis10's avatar
edavis10 committed
21
class IssuesControllerTest < ActionController::TestCase
22 23 24 25
  fixtures :projects,
           :users,
           :roles,
           :members,
26
           :member_roles,
27 28
           :issues,
           :issue_statuses,
29
           :versions,
30
           :trackers,
31
           :projects_trackers,
32 33 34
           :issue_categories,
           :enabled_modules,
           :enumerations,
35
           :attachments,
36 37 38
           :workflows,
           :custom_fields,
           :custom_values,
jplang's avatar
jplang committed
39
           :custom_fields_projects,
40
           :custom_fields_trackers,
41 42
           :time_entries,
           :journals,
edavis10's avatar
edavis10 committed
43 44
           :journal_details,
           :queries
45

46 47 48 49 50 51
  def setup
    @controller = IssuesController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
    User.current = nil
  end
52

53
  def test_index
54
    Setting.default_language = 'en'
55

56 57 58 59 60
    get :index
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_nil assigns(:project)
61 62 63 64 65
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    # private projects hidden
    assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
    assert_no_tag :tag => 'a', :content => /Issue on project 2/
66 67
    # project column
    assert_tag :tag => 'th', :content => /Project/
68
  end
69

70 71 72 73 74 75 76 77 78 79
  def test_index_should_not_list_issues_when_module_disabled
    EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
    get :index
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_nil assigns(:project)
    assert_no_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
  end
80

81 82 83 84 85 86 87 88 89 90
  def test_index_should_not_list_issues_when_module_disabled
    EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
    get :index
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_nil assigns(:project)
    assert_no_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
  end
jplang's avatar
jplang committed
91 92 93 94 95 96 97

  def test_index_should_list_visible_issues_only
    get :index, :per_page => 100
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_nil assigns(:issues).detect {|issue| !issue.visible?}
  end
98

99
  def test_index_with_project
100
    Setting.display_subprojects_issues = 0
101 102 103 104
    get :index, :project_id => 1
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
105 106 107
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_no_tag :tag => 'a', :content => /Subproject issue/
  end
108

109 110 111 112 113 114 115 116 117 118
  def test_index_with_project_and_subprojects
    Setting.display_subprojects_issues = 1
    get :index, :project_id => 1
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
  end
119

120 121 122 123 124 125 126 127 128 129
  def test_index_with_project_and_subprojects_should_show_private_subprojects
    @request.session[:user_id] = 2
    Setting.display_subprojects_issues = 1
    get :index, :project_id => 1
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_tag :tag => 'a', :content => /Can't print recipes/
    assert_tag :tag => 'a', :content => /Subproject issue/
    assert_tag :tag => 'a', :content => /Issue of a private subproject/
130
  end
131

132
  def test_index_with_project_and_default_filter
133 134 135 136
    get :index, :project_id => 1, :set_filter => 1
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
137

138 139 140 141 142
    query = assigns(:query)
    assert_not_nil query
    # default filter
    assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
  end
143

144
  def test_index_with_project_and_filter
145
    get :index, :project_id => 1, :set_filter => 1,
jplang's avatar
jplang committed
146 147
      :f => ['tracker_id'],
      :op => {'tracker_id' => '='},
148
      :v => {'tracker_id' => ['1']}
149 150 151
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
152

153 154 155 156
    query = assigns(:query)
    assert_not_nil query
    assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
  end
157

158 159 160 161 162
  def test_index_with_project_and_empty_filters
    get :index, :project_id => 1, :set_filter => 1, :fields => ['']
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
163

164 165 166 167
    query = assigns(:query)
    assert_not_nil query
    # no filter
    assert_equal({}, query.filters)
168
  end
169

jplang's avatar
jplang committed
170 171 172 173 174 175 176
  def test_index_with_query
    get :index, :project_id => 1, :query_id => 5
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
    assert_nil assigns(:issue_count_by_group)
  end
177

178
  def test_index_with_query_grouped_by_tracker
jplang's avatar
jplang committed
179 180 181 182
    get :index, :project_id => 1, :query_id => 6
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
183
    assert_not_nil assigns(:issue_count_by_group)
184
  end
185

186 187 188 189 190
  def test_index_with_query_grouped_by_list_custom_field
    get :index, :project_id => 1, :query_id => 9
    assert_response :success
    assert_template 'index.rhtml'
    assert_not_nil assigns(:issues)
191
    assert_not_nil assigns(:issue_count_by_group)
jplang's avatar
jplang committed
192
  end
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
  
  def test_private_query_should_not_be_available_to_other_users
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
    @request.session[:user_id] = 3
    
    get :index, :query_id => q.id
    assert_response 403
  end
  
  def test_private_query_should_be_available_to_its_user
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => false, :project => nil)
    @request.session[:user_id] = 2
    
    get :index, :query_id => q.id
    assert_response :success
  end
  
  def test_public_query_should_be_available_to_other_users
    q = Query.create!(:name => "private", :user => User.find(2), :is_public => true, :project => nil)
    @request.session[:user_id] = 3
    
    get :index, :query_id => q.id
    assert_response :success
  end
217

jplang's avatar
jplang committed
218 219 220 221
  def test_index_sort_by_field_not_included_in_columns
    Setting.issue_list_default_columns = %w(subject author)
    get :index, :sort => 'tracker'
  end
222

223
  def test_index_csv_with_project
224
    Setting.default_language = 'en'
225

226 227 228 229
    get :index, :format => 'csv'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'text/csv', @response.content_type
230
    assert @response.body.starts_with?("#,")
231 232 233 234 235 236

    get :index, :project_id => 1, :format => 'csv'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'text/csv', @response.content_type
  end
237

238 239 240 241 242
  def test_index_pdf
    get :index, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
243

244 245 246 247
    get :index, :project_id => 1, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
248

jplang's avatar
jplang committed
249 250 251 252
    get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_equal 'application/pdf', @response.content_type
253
  end
254

255 256 257 258 259 260 261
  def test_index_pdf_with_query_grouped_by_list_custom_field
    get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
    assert_response :success
    assert_not_nil assigns(:issues)
    assert_not_nil assigns(:issue_count_by_group)
    assert_equal 'application/pdf', @response.content_type
  end
262

263
  def test_index_sort
jplang's avatar
jplang committed
264
    get :index, :sort => 'tracker,id:desc'
265
    assert_response :success
266

jplang's avatar
jplang committed
267 268 269
    sort_params = @request.session['issues_index_sort']
    assert sort_params.is_a?(String)
    assert_equal 'tracker,id:desc', sort_params
270

jplang's avatar
jplang committed
271 272 273 274
    issues = assigns(:issues)
    assert_not_nil issues
    assert !issues.empty?
    assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
275
  end
276

277 278
  def test_index_with_columns
    columns = ['tracker', 'subject', 'assigned_to']
279
    get :index, :set_filter => 1, :c => columns
280
    assert_response :success
281

282 283 284 285
    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal columns, query.column_names.map(&:to_s)
286

287 288 289 290
    # columns should be stored in session
    assert_kind_of Hash, session[:query]
    assert_kind_of Array, session[:query][:column_names]
    assert_equal columns, session[:query][:column_names].map(&:to_s)
291 292 293 294 295 296

    # ensure only these columns are kept in the selected columns list
    assert_tag :tag => 'select', :attributes => { :id => 'selected_columns' },
                                 :children => { :count => 3 }
    assert_no_tag :tag => 'option', :attributes => { :value => 'project' },
                                    :parent => { :tag => 'select', :attributes => { :id => "selected_columns" } }
297
  end
298

299 300 301 302
  def test_index_with_custom_field_column
    columns = %w(tracker subject cf_2)
    get :index, :set_filter => 1, :c => columns
    assert_response :success
303

304 305 306 307
    # query should use specified columns
    query = assigns(:query)
    assert_kind_of Query, query
    assert_equal columns, query.column_names.map(&:to_s)
308

309 310 311 312
    assert_tag :td,
      :attributes => {:class => 'cf_2 string'},
      :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
  end
313

314
  def test_show_by_anonymous
jplang's avatar
jplang committed
315 316 317 318
    get :show, :id => 1
    assert_response :success
    assert_template 'show.rhtml'
    assert_not_nil assigns(:issue)
319
    assert_equal Issue.find(1), assigns(:issue)
320

321 322 323
    # anonymous role is allowed to add a note
    assert_tag :tag => 'form',
               :descendant => { :tag => 'fieldset',
324
                                :child => { :tag => 'legend',
325
                                            :content => /Notes/ } }
jplang's avatar
jplang committed
326
  end
327

328 329 330 331
  def test_show_by_manager
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response :success
332

333 334
    assert_tag :tag => 'a',
      :content => /Quote/
335

336 337
    assert_tag :tag => 'form',
               :descendant => { :tag => 'fieldset',
338
                                :child => { :tag => 'legend',
339 340
                                            :content => /Change properties/ } },
               :descendant => { :tag => 'fieldset',
341
                                :child => { :tag => 'legend',
342 343
                                            :content => /Log time/ } },
               :descendant => { :tag => 'fieldset',
344
                                :child => { :tag => 'legend',
345 346
                                            :content => /Notes/ } }
  end
347

348 349 350 351 352 353 354 355 356
  def test_update_form_should_not_display_inactive_enumerations
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response :success

    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
  end
357 358 359 360 361 362 363 364 365 366 367 368
  
  def test_update_form_should_allow_attachment_upload
    @request.session[:user_id] = 2
    get :show, :id => 1
    
    assert_tag :tag => 'form',
      :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
      :descendant => {
        :tag => 'input',
        :attributes => {:type => 'file', :name => 'attachments[1][file]'}
      }
  end
369

jplang's avatar
jplang committed
370 371 372 373 374
  def test_show_should_deny_anonymous_access_without_permission
    Role.anonymous.remove_permission!(:view_issues)
    get :show, :id => 1
    assert_response :redirect
  end
375

jplang's avatar
jplang committed
376 377 378 379 380
  def test_show_should_deny_anonymous_access_to_private_issue
    Issue.update_all(["is_private = ?", true], "id = 1")
    get :show, :id => 1
    assert_response :redirect
  end
381

jplang's avatar
jplang committed
382 383 384 385 386 387
  def test_show_should_deny_non_member_access_without_permission
    Role.non_member.remove_permission!(:view_issues)
    @request.session[:user_id] = 9
    get :show, :id => 1
    assert_response 403
  end
388

jplang's avatar
jplang committed
389 390 391 392 393 394
  def test_show_should_deny_non_member_access_to_private_issue
    Issue.update_all(["is_private = ?", true], "id = 1")
    @request.session[:user_id] = 9
    get :show, :id => 1
    assert_response 403
  end
395

jplang's avatar
jplang committed
396 397 398 399 400 401
  def test_show_should_deny_member_access_without_permission
    Role.find(1).remove_permission!(:view_issues)
    @request.session[:user_id] = 2
    get :show, :id => 1
    assert_response 403
  end
402

jplang's avatar
jplang committed
403 404 405 406 407 408
  def test_show_should_deny_member_access_to_private_issue_without_permission
    Issue.update_all(["is_private = ?", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response 403
  end
409

jplang's avatar
jplang committed
410 411 412 413 414 415
  def test_show_should_allow_author_access_to_private_issue
    Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
416

jplang's avatar
jplang committed
417 418 419 420 421 422
  def test_show_should_allow_assignee_access_to_private_issue
    Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
423

jplang's avatar
jplang committed
424 425 426 427 428 429 430
  def test_show_should_allow_member_access_to_private_issue_with_permission
    Issue.update_all(["is_private = ?", true], "id = 1")
    User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
    @request.session[:user_id] = 3
    get :show, :id => 1
    assert_response :success
  end
431

432 433 434 435 436
  def test_show_should_not_disclose_relations_to_invisible_issues
    Setting.cross_project_issue_relations = '1'
    IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
    # Relation to a private project issue
    IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
437

438 439
    get :show, :id => 1
    assert_response :success
440

441 442 443 444 445
    assert_tag :div, :attributes => { :id => 'relations' },
                     :descendant => { :tag => 'a', :content => /#2$/ }
    assert_no_tag :div, :attributes => { :id => 'relations' },
                        :descendant => { :tag => 'a', :content => /#4$/ }
  end
446

447 448 449
  def test_show_atom
    get :show, :id => 2, :format => 'atom'
    assert_response :success
450
    assert_template 'journals/index.rxml'
451
    # Inline image
452
    assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
453
  end
454

jplang's avatar
jplang committed
455
  def test_show_export_to_pdf
456
    get :show, :id => 3, :format => 'pdf'
jplang's avatar
jplang committed
457 458 459 460 461 462
    assert_response :success
    assert_equal 'application/pdf', @response.content_type
    assert @response.body.starts_with?('%PDF')
    assert_not_nil assigns(:issue)
  end

463 464 465 466 467
  def test_get_new
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :tracker_id => 1
    assert_response :success
    assert_template 'new'
468

469
    assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
470
                                                 :value => 'Default string' }
471 472 473 474 475

    # Be sure we don't display inactive IssuePriorities
    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
476
  end
477 478 479 480 481 482 483 484 485 486 487 488
  
  def test_get_new_form_should_allow_attachment_upload
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :tracker_id => 1
    
    assert_tag :tag => 'form',
      :attributes => {:id => 'issue-form', :method => 'post', :enctype => 'multipart/form-data'},
      :descendant => {
        :tag => 'input',
        :attributes => {:type => 'file', :name => 'attachments[1][file]'}
      }
  end
489 490 491 492 493 494

  def test_get_new_without_tracker_id
    @request.session[:user_id] = 2
    get :new, :project_id => 1
    assert_response :success
    assert_template 'new'
495

496 497 498 499
    issue = assigns(:issue)
    assert_not_nil issue
    assert_equal Project.find(1).trackers.first, issue.tracker
  end
500

501 502 503
  def test_get_new_with_no_default_status_should_display_an_error
    @request.session[:user_id] = 2
    IssueStatus.delete_all
504

505 506
    get :new, :project_id => 1
    assert_response 500
507
    assert_error_tag :content => /No default issue/
508
  end
509

510 511 512
  def test_get_new_with_no_tracker_should_display_an_error
    @request.session[:user_id] = 2
    Tracker.delete_all
513

514 515
    get :new, :project_id => 1
    assert_response 500
516
    assert_error_tag :content => /No tracker/
517
  end
518

519 520
  def test_update_new_form
    @request.session[:user_id] = 2
521
    xhr :post, :new, :project_id => 1,
522
                     :issue => {:tracker_id => 2,
523 524 525 526
                                :subject => 'This is the test_new issue',
                                :description => 'This is the description',
                                :priority_id => 5}
    assert_response :success
527
    assert_template 'attributes'
528

529 530 531 532 533 534
    issue = assigns(:issue)
    assert_kind_of Issue, issue
    assert_equal 1, issue.project_id
    assert_equal 2, issue.tracker_id
    assert_equal 'This is the test_new issue', issue.subject
  end
535

536
  def test_post_create
537
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
538
    assert_difference 'Issue.count' do
539
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
540
                 :issue => {:tracker_id => 3,
541
                            :status_id => 2,
edavis10's avatar
edavis10 committed
542 543 544
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
545
                            :start_date => '2010-11-07',
edavis10's avatar
edavis10 committed
546 547 548 549
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
550

551 552 553
    issue = Issue.find_by_subject('This is the test_new issue')
    assert_not_nil issue
    assert_equal 2, issue.author_id
554
    assert_equal 3, issue.tracker_id
555
    assert_equal 2, issue.status_id
556
    assert_equal Date.parse('2010-11-07'), issue.start_date
557
    assert_nil issue.estimated_hours
558
    v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
559 560
    assert_not_nil v
    assert_equal 'Value for field 2', v.value
561
  end
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
  
  def test_post_new_with_group_assignment
    group = Group.find(11)
    project = Project.find(1)
    project.members << Member.new(:principal => group, :roles => [Role.first])

    with_settings :issue_group_assignment => '1' do
      @request.session[:user_id] = 2
      assert_difference 'Issue.count' do
        post :create, :project_id => project.id, 
                      :issue => {:tracker_id => 3,
                                 :status_id => 1,
                                 :subject => 'This is the test_new_with_group_assignment issue',
                                 :assigned_to_id => group.id}
      end
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
    
    issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
    assert_not_nil issue
    assert_equal group, issue.assigned_to
  end
584

585 586 587
  def test_post_create_without_start_date
    @request.session[:user_id] = 2
    assert_difference 'Issue.count' do
588
      post :create, :project_id => 1,
589 590 591 592 593 594 595 596 597 598
                 :issue => {:tracker_id => 3,
                            :status_id => 2,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :start_date => '',
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
599

600 601 602 603
    issue = Issue.find_by_subject('This is the test_new issue')
    assert_not_nil issue
    assert_nil issue.start_date
  end
604

605
  def test_post_create_and_continue
606
    @request.session[:user_id] = 2
607 608 609 610 611 612 613 614 615 616
    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
        :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
        :continue => ''
    end
    
    issue = Issue.first(:order => 'id DESC')
    assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
    assert_not_nil flash[:notice], "flash was not set"
    assert flash[:notice].include?("<a href='/issues/#{issue.id}'>##{issue.id}</a>"), "issue link not found in flash: #{flash[:notice]}"
617
  end
618

619
  def test_post_create_without_custom_fields_param
620
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
621
    assert_difference 'Issue.count' do
622
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
623 624 625 626 627 628
                 :issue => {:tracker_id => 1,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
629
  end
630

631
  def test_post_create_with_required_custom_field_and_without_custom_fields_param
632 633 634 635
    field = IssueCustomField.find_by_name('Database')
    field.update_attribute(:is_required, true)

    @request.session[:user_id] = 2
636
    post :create, :project_id => 1,
637 638 639 640 641 642 643 644
               :issue => {:tracker_id => 1,
                          :subject => 'This is the test_new issue',
                          :description => 'This is the description',
                          :priority_id => 5}
    assert_response :success
    assert_template 'new'
    issue = assigns(:issue)
    assert_not_nil issue
645
    assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
646
  end
647

648
  def test_post_create_with_watchers
649 650
    @request.session[:user_id] = 2
    ActionMailer::Base.deliveries.clear
651

652
    assert_difference 'Watcher.count', 2 do
653
      post :create, :project_id => 1,
654 655 656 657 658 659 660
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a new issue with watchers',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :watcher_user_ids => ['2', '3']}
    end
    issue = Issue.find_by_subject('This is a new issue with watchers')
jplang's avatar
jplang committed
661 662
    assert_not_nil issue
    assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
663

664 665 666 667 668 669 670 671
    # Watchers added
    assert_equal [2, 3], issue.watcher_user_ids.sort
    assert issue.watched_by?(User.find(3))
    # Watchers notified
    mail = ActionMailer::Base.deliveries.last
    assert_kind_of TMail::Mail, mail
    assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
  end
672

673
  def test_post_create_subissue
jplang's avatar
jplang committed
674
    @request.session[:user_id] = 2
675

jplang's avatar
jplang committed
676
    assert_difference 'Issue.count' do
677
      post :create, :project_id => 1,
jplang's avatar
jplang committed
678 679 680 681 682 683 684 685
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a child issue',
                            :parent_issue_id => 2}
    end
    issue = Issue.find_by_subject('This is a child issue')
    assert_not_nil issue
    assert_equal Issue.find(2), issue.parent
  end
686 687 688

  def test_post_create_subissue_with_non_numeric_parent_id
    @request.session[:user_id] = 2
689

690
    assert_difference 'Issue.count' do
691
      post :create, :project_id => 1,
692 693 694 695 696 697 698 699
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a child issue',
                            :parent_issue_id => 'ABC'}
    end
    issue = Issue.find_by_subject('This is a child issue')
    assert_not_nil issue
    assert_nil issue.parent
  end
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
  
  def test_post_create_private
    @request.session[:user_id] = 2

    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a private issue',
                            :is_private => '1'}
    end
    issue = Issue.first(:order => 'id DESC')
    assert issue.is_private?
  end
  
  def test_post_create_private_with_set_own_issues_private_permission
    role = Role.find(1)
    role.remove_permission! :set_issues_private
    role.add_permission! :set_own_issues_private
    
    @request.session[:user_id] = 2

    assert_difference 'Issue.count' do
      post :create, :project_id => 1,
                 :issue => {:tracker_id => 1,
                            :subject => 'This is a private issue',
                            :is_private => '1'}
    end
    issue = Issue.first(:order => 'id DESC')
    assert issue.is_private?
  end
730

731
  def test_post_create_should_send_a_notification
732 733
    ActionMailer::Base.deliveries.clear
    @request.session[:user_id] = 2
edavis10's avatar
edavis10 committed
734
    assert_difference 'Issue.count' do
735
      post :create, :project_id => 1,
edavis10's avatar
edavis10 committed
736 737 738 739 740 741 742 743
                 :issue => {:tracker_id => 3,
                            :subject => 'This is the test_new issue',
                            :description => 'This is the description',
                            :priority_id => 5,
                            :estimated_hours => '',
                            :custom_field_values => {'2' => 'Value for field 2'}}
    end
    assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
744

745 746
    assert_equal 1, ActionMailer::Base.deliveries.size
  end
747

748
  def test_post_create_should_preserve_fields_values_on_validation_failure
749
    @request.session[:user_id] = 2
750
    post :create, :project_id => 1,
751
               :issue => {:tracker_id => 1,
752 753 754
                          # empty subject
                          :subject => '',
                          :description => 'This is a description',
755 756 757 758
                          :priority_id => 6,
                          :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
    assert_response :success
    assert_template 'new'
759

760 761
    assert_tag :textarea, :attributes => { :name => 'issue[description]' },
                          :content => 'This is a description'
762 763 764
    assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
                        :child => { :tag => 'option', :attributes => { :selected => 'selected',
                                                                       :value => '6' },
765
                                                      :content => 'High' }
766 767 768 769
    # Custom fields
    assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
                        :child => { :tag => 'option', :attributes => { :selected => 'selected',
                                                                       :value => 'Oracle' },
770
                                                      :content => 'Oracle' }
771 772 773
    assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
                                        :value => 'Value for field 2'}
  end
774

775
  def test_post_create_should_ignore_non_safe_attributes
776 777
    @request.session[:user_id] = 2
    assert_nothing_raised do
778
      post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
779 780
    end
  end
781

782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
  def test_post_create_with_attachment
    set_tmp_attachments_directory
    @request.session[:user_id] = 2
    
    assert_difference 'Issue.count' do
      assert_difference 'Attachment.count' do
        post :create, :project_id => 1, 
          :issue => { :tracker_id => '1', :subject => 'With attachment' },
          :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
      end
    end
    
    issue = Issue.first(:order => 'id DESC')
    attachment = Attachment.first(:order => 'id DESC')
    
    assert_equal issue, attachment.container
    assert_equal 2, attachment.author_id
    assert_equal 'testfile.txt', attachment.filename
    assert_equal 'text/plain', attachment.content_type
    assert_equal 'test file', attachment.description
    assert_equal 59, attachment.filesize
    assert File.exists?(attachment.diskfile)
    assert_equal 59, File.size(attachment.diskfile)
  end

807 808 809
  context "without workflow privilege" do
    setup do
      Workflow.delete_all(["role_id = ?", Role.anonymous.id])
810
      Role.anonymous.add_permission! :add_issues, :add_issue_notes
811
    end
812

813 814 815 816 817 818 819 820 821 822
    context "#new" do
      should "propose default status only" do
        get :new, :project_id => 1
        assert_response :success
        assert_template 'new'
        assert_tag :tag => 'select',
          :attributes => {:name => 'issue[status_id]'},
          :children => {:count => 1},
          :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
      end
823

824 825
      should "accept default status" do
        assert_difference 'Issue.count' do
826
          post :create, :project_id => 1,
827 828 829 830 831 832 833
                     :issue => {:tracker_id => 1,
                                :subject => 'This is an issue',
                                :status_id => 1}
        end
        issue = Issue.last(:order => 'id')
        assert_equal IssueStatus.default, issue.status
      end
834

835 836
      should "ignore unauthorized status" do
        assert_difference 'Issue.count' do
837
          post :create, :project_id => 1,
838 839 840 841 842 843 844 845
                     :issue => {:tracker_id => 1,
                                :subject => 'This is an issue',
                                :status_id => 3}
        end
        issue = Issue.last(:order => 'id')
        assert_equal IssueStatus.default, issue.status
      end
    end
846

847 848 849 850 851 852 853
    context "#update" do
      should "ignore status change" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 1, Issue.find(1).status_id
      end
854

855 856 857 858 859 860 861 862 863 864
      should "ignore attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal "Can't print recipes", issue.subject
        assert_nil issue.assigned_to
      end
    end
  end
865

866 867 868 869 870 871 872
  context "with workflow privilege" do
    setup do
      Workflow.delete_all(["role_id = ?", Role.anonymous.id])
      Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
      Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
      Role.anonymous.add_permission! :add_issues, :add_issue_notes
    end
873

874 875 876 877 878 879 880
    context "#update" do
      should "accept authorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 3, Issue.find(1).status_id
      end
881

882 883 884 885 886 887
      should "ignore unauthorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
        end
        assert_equal 1, Issue.find(1).status_id
      end
888

889 890 891 892 893 894 895
      should "accept authorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal 2, issue.assigned_to_id
      end
896

897 898 899 900 901 902 903 904
      should "ignore unauthorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
        end
        issue = Issue.find(1)
        assert_equal "Can't print recipes", issue.subject
      end
    end
905

906 907 908 909 910 911 912 913 914 915 916
    context "and :edit_issues permission" do
      setup do
        Role.anonymous.add_permission! :add_issues, :edit_issues
      end

      should "accept authorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
        end
        assert_equal 3, Issue.find(1).status_id
      end
917

918 919 920 921 922 923
      should "ignore unauthorized status" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
        end
        assert_equal 1, Issue.find(1).status_id
      end
924

925 926 927 928 929 930 931 932 933
      should "accept authorized attributes changes" do
        assert_difference 'Journal.count' do
          put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
        end
        issue = Issue.find(1)
        assert_equal "changed", issue.subject
        assert_equal 2, issue.assigned_to_id
      end
    end
934
  end
935

936 937 938 939 940 941 942 943
  def test_copy_issue
    @request.session[:user_id] = 2
    get :new, :project_id => 1, :copy_from => 1
    assert_template 'new'
    assert_not_nil assigns(:issue)
    orig = Issue.find(1)
    assert_equal orig.subject, assigns(:issue).subject
  end
944

jplang's avatar
jplang committed
945 946 947 948 949 950 951
  def test_get_edit
    @request.session[:user_id] = 2
    get :edit, :id => 1
    assert_response :success
    assert_template 'edit'
    assert_not_nil assigns(:issue)
    assert_equal Issue.find(1), assigns(:issue)
952 953 954 955 956

    # Be sure we don't display inactive IssuePriorities
    assert ! IssuePriority.find(15).active?
    assert_no_tag :option, :attributes => {:value => '15'},
                           :parent => {:tag => 'select', :attributes => {:id => 'issue_priority_id'} }
jplang's avatar
jplang committed
957
  end
958

959 960
  def test_get_edit_with_params
    @request.session[:user_id] = 2
961 962
    get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
        :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
963 964
    assert_response :success
    assert_template 'edit'
965

966 967
    issue = assigns(:issue)
    assert_not_nil issue
968

969 970
    assert_equal 5, issue.status_id
    assert_tag :select, :attributes => { :name => 'issue[status_id]' },
971
                        :child => { :tag => 'option',
972 973
                                    :content => 'Closed',
                                    :attributes => { :selected => 'selected' } }
974

975 976
    assert_equal 7, issue.priority_id
    assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
977
                        :child => { :tag => 'option',
978 979
                                    :content => 'Urgent',
                                    :attributes => { :selected => 'selected' } }
980 981 982 983 984 985

    assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
    assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
                        :child => { :tag => 'option',
                                    :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
    assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
986
  end
987 988 989

  def test_update_edit_form
    @request.session[:user_id] = 2
990
    xhr :post, :new, :project_id => 1,
991