You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

projects_controller_test.rb 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. # Redmine - project management software
  2. # Copyright (C) 2006-2012 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. require File.expand_path('../../test_helper', __FILE__)
  18. require 'projects_controller'
  19. # Re-raise errors caught by the controller.
  20. class ProjectsController; def rescue_action(e) raise e end; end
  21. class ProjectsControllerTest < ActionController::TestCase
  22. fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
  23. :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
  24. :attachments, :custom_fields, :custom_values, :time_entries
  25. def setup
  26. @controller = ProjectsController.new
  27. @request = ActionController::TestRequest.new
  28. @response = ActionController::TestResponse.new
  29. @request.session[:user_id] = nil
  30. Setting.default_language = 'en'
  31. end
  32. def test_index
  33. get :index
  34. assert_response :success
  35. assert_template 'index'
  36. assert_not_nil assigns(:projects)
  37. assert_tag :ul, :child => {:tag => 'li',
  38. :descendant => {:tag => 'a', :content => 'eCookbook'},
  39. :child => { :tag => 'ul',
  40. :descendant => { :tag => 'a',
  41. :content => 'Child of private child'
  42. }
  43. }
  44. }
  45. assert_no_tag :a, :content => /Private child of eCookbook/
  46. end
  47. def test_index_atom
  48. get :index, :format => 'atom'
  49. assert_response :success
  50. assert_template 'common/feed'
  51. assert_select 'feed>title', :text => 'Redmine: Latest projects'
  52. assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_condition(User.current))
  53. end
  54. context "#index" do
  55. context "by non-admin user with view_time_entries permission" do
  56. setup do
  57. @request.session[:user_id] = 3
  58. end
  59. should "show overall spent time link" do
  60. get :index
  61. assert_template 'index'
  62. assert_tag :a, :attributes => {:href => '/time_entries'}
  63. end
  64. end
  65. context "by non-admin user without view_time_entries permission" do
  66. setup do
  67. Role.find(2).remove_permission! :view_time_entries
  68. Role.non_member.remove_permission! :view_time_entries
  69. Role.anonymous.remove_permission! :view_time_entries
  70. @request.session[:user_id] = 3
  71. end
  72. should "not show overall spent time link" do
  73. get :index
  74. assert_template 'index'
  75. assert_no_tag :a, :attributes => {:href => '/time_entries'}
  76. end
  77. end
  78. end
  79. context "#new" do
  80. context "by admin user" do
  81. setup do
  82. @request.session[:user_id] = 1
  83. end
  84. should "accept get" do
  85. get :new
  86. assert_response :success
  87. assert_template 'new'
  88. end
  89. end
  90. context "by non-admin user with add_project permission" do
  91. setup do
  92. Role.non_member.add_permission! :add_project
  93. @request.session[:user_id] = 9
  94. end
  95. should "accept get" do
  96. get :new
  97. assert_response :success
  98. assert_template 'new'
  99. assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}
  100. end
  101. end
  102. context "by non-admin user with add_subprojects permission" do
  103. setup do
  104. Role.find(1).remove_permission! :add_project
  105. Role.find(1).add_permission! :add_subprojects
  106. @request.session[:user_id] = 2
  107. end
  108. should "accept get" do
  109. get :new, :parent_id => 'ecookbook'
  110. assert_response :success
  111. assert_template 'new'
  112. # parent project selected
  113. assert_tag :select, :attributes => {:name => 'project[parent_id]'},
  114. :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
  115. # no empty value
  116. assert_no_tag :select, :attributes => {:name => 'project[parent_id]'},
  117. :child => {:tag => 'option', :attributes => {:value => ''}}
  118. end
  119. end
  120. end
  121. context "POST :create" do
  122. context "by admin user" do
  123. setup do
  124. @request.session[:user_id] = 1
  125. end
  126. should "create a new project" do
  127. post :create,
  128. :project => {
  129. :name => "blog",
  130. :description => "weblog",
  131. :homepage => 'http://weblog',
  132. :identifier => "blog",
  133. :is_public => 1,
  134. :custom_field_values => { '3' => 'Beta' },
  135. :tracker_ids => ['1', '3'],
  136. # an issue custom field that is not for all project
  137. :issue_custom_field_ids => ['9'],
  138. :enabled_module_names => ['issue_tracking', 'news', 'repository']
  139. }
  140. assert_redirected_to '/projects/blog/settings'
  141. project = Project.find_by_name('blog')
  142. assert_kind_of Project, project
  143. assert project.active?
  144. assert_equal 'weblog', project.description
  145. assert_equal 'http://weblog', project.homepage
  146. assert_equal true, project.is_public?
  147. assert_nil project.parent
  148. assert_equal 'Beta', project.custom_value_for(3).value
  149. assert_equal [1, 3], project.trackers.map(&:id).sort
  150. assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
  151. assert project.issue_custom_fields.include?(IssueCustomField.find(9))
  152. end
  153. should "create a new subproject" do
  154. post :create, :project => { :name => "blog",
  155. :description => "weblog",
  156. :identifier => "blog",
  157. :is_public => 1,
  158. :custom_field_values => { '3' => 'Beta' },
  159. :parent_id => 1
  160. }
  161. assert_redirected_to '/projects/blog/settings'
  162. project = Project.find_by_name('blog')
  163. assert_kind_of Project, project
  164. assert_equal Project.find(1), project.parent
  165. end
  166. should "continue" do
  167. assert_difference 'Project.count' do
  168. post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
  169. end
  170. assert_redirected_to '/projects/new?'
  171. end
  172. end
  173. context "by non-admin user with add_project permission" do
  174. setup do
  175. Role.non_member.add_permission! :add_project
  176. @request.session[:user_id] = 9
  177. end
  178. should "accept create a Project" do
  179. post :create, :project => { :name => "blog",
  180. :description => "weblog",
  181. :identifier => "blog",
  182. :is_public => 1,
  183. :custom_field_values => { '3' => 'Beta' },
  184. :tracker_ids => ['1', '3'],
  185. :enabled_module_names => ['issue_tracking', 'news', 'repository']
  186. }
  187. assert_redirected_to '/projects/blog/settings'
  188. project = Project.find_by_name('blog')
  189. assert_kind_of Project, project
  190. assert_equal 'weblog', project.description
  191. assert_equal true, project.is_public?
  192. assert_equal [1, 3], project.trackers.map(&:id).sort
  193. assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
  194. # User should be added as a project member
  195. assert User.find(9).member_of?(project)
  196. assert_equal 1, project.members.size
  197. end
  198. should "fail with parent_id" do
  199. assert_no_difference 'Project.count' do
  200. post :create, :project => { :name => "blog",
  201. :description => "weblog",
  202. :identifier => "blog",
  203. :is_public => 1,
  204. :custom_field_values => { '3' => 'Beta' },
  205. :parent_id => 1
  206. }
  207. end
  208. assert_response :success
  209. project = assigns(:project)
  210. assert_kind_of Project, project
  211. assert_not_nil project.errors[:parent_id]
  212. end
  213. end
  214. context "by non-admin user with add_subprojects permission" do
  215. setup do
  216. Role.find(1).remove_permission! :add_project
  217. Role.find(1).add_permission! :add_subprojects
  218. @request.session[:user_id] = 2
  219. end
  220. should "create a project with a parent_id" do
  221. post :create, :project => { :name => "blog",
  222. :description => "weblog",
  223. :identifier => "blog",
  224. :is_public => 1,
  225. :custom_field_values => { '3' => 'Beta' },
  226. :parent_id => 1
  227. }
  228. assert_redirected_to '/projects/blog/settings'
  229. project = Project.find_by_name('blog')
  230. end
  231. should "fail without parent_id" do
  232. assert_no_difference 'Project.count' do
  233. post :create, :project => { :name => "blog",
  234. :description => "weblog",
  235. :identifier => "blog",
  236. :is_public => 1,
  237. :custom_field_values => { '3' => 'Beta' }
  238. }
  239. end
  240. assert_response :success
  241. project = assigns(:project)
  242. assert_kind_of Project, project
  243. assert_not_nil project.errors[:parent_id]
  244. end
  245. should "fail with unauthorized parent_id" do
  246. assert !User.find(2).member_of?(Project.find(6))
  247. assert_no_difference 'Project.count' do
  248. post :create, :project => { :name => "blog",
  249. :description => "weblog",
  250. :identifier => "blog",
  251. :is_public => 1,
  252. :custom_field_values => { '3' => 'Beta' },
  253. :parent_id => 6
  254. }
  255. end
  256. assert_response :success
  257. project = assigns(:project)
  258. assert_kind_of Project, project
  259. assert_not_nil project.errors[:parent_id]
  260. end
  261. end
  262. end
  263. def test_create_should_preserve_modules_on_validation_failure
  264. with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
  265. @request.session[:user_id] = 1
  266. assert_no_difference 'Project.count' do
  267. post :create, :project => {
  268. :name => "blog",
  269. :identifier => "",
  270. :enabled_module_names => %w(issue_tracking news)
  271. }
  272. end
  273. assert_response :success
  274. project = assigns(:project)
  275. assert_equal %w(issue_tracking news), project.enabled_module_names.sort
  276. end
  277. end
  278. def test_show_by_id
  279. get :show, :id => 1
  280. assert_response :success
  281. assert_template 'show'
  282. assert_not_nil assigns(:project)
  283. end
  284. def test_show_by_identifier
  285. get :show, :id => 'ecookbook'
  286. assert_response :success
  287. assert_template 'show'
  288. assert_not_nil assigns(:project)
  289. assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
  290. assert_tag 'li', :content => /Development status/
  291. end
  292. def test_show_should_not_display_hidden_custom_fields
  293. ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
  294. get :show, :id => 'ecookbook'
  295. assert_response :success
  296. assert_template 'show'
  297. assert_not_nil assigns(:project)
  298. assert_no_tag 'li', :content => /Development status/
  299. end
  300. def test_show_should_not_fail_when_custom_values_are_nil
  301. project = Project.find_by_identifier('ecookbook')
  302. project.custom_values.first.update_attribute(:value, nil)
  303. get :show, :id => 'ecookbook'
  304. assert_response :success
  305. assert_template 'show'
  306. assert_not_nil assigns(:project)
  307. assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
  308. end
  309. def show_archived_project_should_be_denied
  310. project = Project.find_by_identifier('ecookbook')
  311. project.archive!
  312. get :show, :id => 'ecookbook'
  313. assert_response 403
  314. assert_nil assigns(:project)
  315. assert_tag :tag => 'p', :content => /archived/
  316. end
  317. def test_private_subprojects_hidden
  318. get :show, :id => 'ecookbook'
  319. assert_response :success
  320. assert_template 'show'
  321. assert_no_tag :tag => 'a', :content => /Private child/
  322. end
  323. def test_private_subprojects_visible
  324. @request.session[:user_id] = 2 # manager who is a member of the private subproject
  325. get :show, :id => 'ecookbook'
  326. assert_response :success
  327. assert_template 'show'
  328. assert_tag :tag => 'a', :content => /Private child/
  329. end
  330. def test_settings
  331. @request.session[:user_id] = 2 # manager
  332. get :settings, :id => 1
  333. assert_response :success
  334. assert_template 'settings'
  335. end
  336. def test_update
  337. @request.session[:user_id] = 2 # manager
  338. post :update, :id => 1, :project => {:name => 'Test changed name',
  339. :issue_custom_field_ids => ['']}
  340. assert_redirected_to '/projects/ecookbook/settings'
  341. project = Project.find(1)
  342. assert_equal 'Test changed name', project.name
  343. end
  344. def test_update_with_failure
  345. @request.session[:user_id] = 2 # manager
  346. post :update, :id => 1, :project => {:name => ''}
  347. assert_response :success
  348. assert_template 'settings'
  349. assert_error_tag :content => /name can't be blank/i
  350. end
  351. def test_modules
  352. @request.session[:user_id] = 2
  353. Project.find(1).enabled_module_names = ['issue_tracking', 'news']
  354. post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
  355. assert_redirected_to '/projects/ecookbook/settings/modules'
  356. assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
  357. end
  358. def test_destroy_without_confirmation
  359. @request.session[:user_id] = 1 # admin
  360. delete :destroy, :id => 1
  361. assert_response :success
  362. assert_template 'destroy'
  363. assert_not_nil Project.find_by_id(1)
  364. end
  365. def test_destroy
  366. @request.session[:user_id] = 1 # admin
  367. delete :destroy, :id => 1, :confirm => 1
  368. assert_redirected_to '/admin/projects'
  369. assert_nil Project.find_by_id(1)
  370. end
  371. def test_archive
  372. @request.session[:user_id] = 1 # admin
  373. post :archive, :id => 1
  374. assert_redirected_to '/admin/projects'
  375. assert !Project.find(1).active?
  376. end
  377. def test_archive_with_failure
  378. @request.session[:user_id] = 1
  379. Project.any_instance.stubs(:archive).returns(false)
  380. post :archive, :id => 1
  381. assert_redirected_to '/admin/projects'
  382. assert_match /project cannot be archived/i, flash[:error]
  383. end
  384. def test_unarchive
  385. @request.session[:user_id] = 1 # admin
  386. Project.find(1).archive
  387. post :unarchive, :id => 1
  388. assert_redirected_to '/admin/projects'
  389. assert Project.find(1).active?
  390. end
  391. def test_project_breadcrumbs_should_be_limited_to_3_ancestors
  392. CustomField.delete_all
  393. parent = nil
  394. 6.times do |i|
  395. p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")
  396. p.set_parent!(parent)
  397. get :show, :id => p
  398. assert_tag :h1, :parent => { :attributes => {:id => 'header'}},
  399. :children => { :count => [i, 3].min,
  400. :only => { :tag => 'a' } }
  401. parent = p
  402. end
  403. end
  404. def test_get_copy
  405. @request.session[:user_id] = 1 # admin
  406. get :copy, :id => 1
  407. assert_response :success
  408. assert_template 'copy'
  409. assert assigns(:project)
  410. assert_equal Project.find(1).description, assigns(:project).description
  411. assert_nil assigns(:project).id
  412. assert_tag :tag => 'input',
  413. :attributes => {:name => 'project[enabled_module_names][]', :value => 'issue_tracking'}
  414. end
  415. def test_post_copy_should_copy_requested_items
  416. @request.session[:user_id] = 1 # admin
  417. CustomField.delete_all
  418. assert_difference 'Project.count' do
  419. post :copy, :id => 1,
  420. :project => {
  421. :name => 'Copy',
  422. :identifier => 'unique-copy',
  423. :tracker_ids => ['1', '2', '3', ''],
  424. :enabled_module_names => %w(issue_tracking time_tracking)
  425. },
  426. :only => %w(issues versions)
  427. end
  428. project = Project.find('unique-copy')
  429. source = Project.find(1)
  430. assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
  431. assert_equal source.versions.count, project.versions.count, "All versions were not copied"
  432. # issues assigned to a closed version won't be copied
  433. assert_equal source.issues.select {|i| i.fixed_version.nil? || i.fixed_version.open?}.size,
  434. project.issues.count, "All issues were not copied"
  435. assert_equal 0, project.members.count
  436. end
  437. def test_post_copy_should_redirect_to_settings_when_successful
  438. @request.session[:user_id] = 1 # admin
  439. post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
  440. assert_response :redirect
  441. assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
  442. end
  443. def test_jump_should_redirect_to_active_tab
  444. get :show, :id => 1, :jump => 'issues'
  445. assert_redirected_to '/projects/ecookbook/issues'
  446. end
  447. def test_jump_should_not_redirect_to_inactive_tab
  448. get :show, :id => 3, :jump => 'documents'
  449. assert_response :success
  450. assert_template 'show'
  451. end
  452. def test_jump_should_not_redirect_to_unknown_tab
  453. get :show, :id => 3, :jump => 'foobar'
  454. assert_response :success
  455. assert_template 'show'
  456. end
  457. end