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.

repositories_git_controller_test.rb 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. # Redmine - project management software
  2. # Copyright (C) 2006-2016 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. class RepositoriesGitControllerTest < Redmine::ControllerTest
  19. tests RepositoriesController
  20. fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
  21. :repositories, :enabled_modules
  22. REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
  23. REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
  24. PRJ_ID = 3
  25. CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
  26. FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
  27. NUM_REV = 28
  28. ## Git, Mercurial and CVS path encodings are binary.
  29. ## Subversion supports URL encoding for path.
  30. ## Redmine Mercurial adapter and extension use URL encoding.
  31. ## Git accepts only binary path in command line parameter.
  32. ## So, there is no way to use binary command line parameter in JRuby.
  33. JRUBY_SKIP = (RUBY_PLATFORM == 'java')
  34. JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
  35. def setup
  36. @ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
  37. User.current = nil
  38. @project = Project.find(PRJ_ID)
  39. @repository = Repository::Git.create(
  40. :project => @project,
  41. :url => REPOSITORY_PATH,
  42. :path_encoding => 'ISO-8859-1'
  43. )
  44. assert @repository
  45. end
  46. def test_create_and_update
  47. @request.session[:user_id] = 1
  48. assert_difference 'Repository.count' do
  49. post :create, :project_id => 'subproject1',
  50. :repository_scm => 'Git',
  51. :repository => {
  52. :url => '/test',
  53. :is_default => '0',
  54. :identifier => 'test-create',
  55. :report_last_commit => '1',
  56. }
  57. end
  58. assert_response 302
  59. repository = Repository.order('id DESC').first
  60. assert_kind_of Repository::Git, repository
  61. assert_equal '/test', repository.url
  62. assert_equal true, repository.report_last_commit
  63. put :update, :id => repository.id,
  64. :repository => {
  65. :report_last_commit => '0'
  66. }
  67. assert_response 302
  68. repo2 = Repository.find(repository.id)
  69. assert_equal false, repo2.report_last_commit
  70. end
  71. if File.directory?(REPOSITORY_PATH)
  72. ## Ruby uses ANSI api to fork a process on Windows.
  73. ## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
  74. ## and these are incompatible with ASCII.
  75. ## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
  76. ## http://code.google.com/p/msysgit/issues/detail?id=80
  77. ## So, Latin-1 path tests fail on Japanese Windows
  78. WINDOWS_PASS = (Redmine::Platform.mswin? &&
  79. Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
  80. WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
  81. def test_get_new
  82. @request.session[:user_id] = 1
  83. @project.repository.destroy
  84. get :new, :project_id => 'subproject1', :repository_scm => 'Git'
  85. assert_response :success
  86. assert_select 'select[name=?]', 'repository_scm' do
  87. assert_select 'option[value=?][selected=selected]', 'Git'
  88. end
  89. end
  90. def test_browse_root
  91. assert_equal 0, @repository.changesets.count
  92. @repository.fetch_changesets
  93. @project.reload
  94. assert_equal NUM_REV, @repository.changesets.count
  95. get :show, :id => PRJ_ID
  96. assert_response :success
  97. assert_select 'table.entries tbody' do
  98. assert_select 'tr', 9
  99. assert_select 'tr.dir td.filename_no_report a', :text => 'images'
  100. assert_select 'tr.dir td.filename_no_report a', :text => 'this_is_a_really_long_and_verbose_directory_name'
  101. assert_select 'tr.dir td.filename_no_report a', :text => 'sources'
  102. assert_select 'tr.file td.filename_no_report a', :text => 'README'
  103. assert_select 'tr.file td.filename_no_report a', :text => 'copied_README'
  104. assert_select 'tr.file td.filename_no_report a', :text => 'new_file.txt'
  105. assert_select 'tr.file td.filename_no_report a', :text => 'renamed_test.txt'
  106. assert_select 'tr.file td.filename_no_report a', :text => 'filemane with spaces.txt'
  107. assert_select 'tr.file td.filename_no_report a', :text => 'filename with a leading space.txt'
  108. end
  109. assert_select 'table.changesets tbody' do
  110. assert_select 'tr'
  111. end
  112. end
  113. def test_browse_branch
  114. assert_equal 0, @repository.changesets.count
  115. @repository.fetch_changesets
  116. @project.reload
  117. assert_equal NUM_REV, @repository.changesets.count
  118. get :show, :id => PRJ_ID, :rev => 'test_branch'
  119. assert_response :success
  120. assert_select 'table.entries tbody' do
  121. assert_select 'tr', 4
  122. assert_select 'tr.dir td.filename_no_report a', :text => 'images'
  123. assert_select 'tr.dir td.filename_no_report a', :text => 'sources'
  124. assert_select 'tr.file td.filename_no_report a', :text => 'README'
  125. assert_select 'tr.file td.filename_no_report a', :text => 'test.txt'
  126. end
  127. assert_select 'table.changesets tbody' do
  128. assert_select 'tr'
  129. end
  130. end
  131. def test_browse_tag
  132. assert_equal 0, @repository.changesets.count
  133. @repository.fetch_changesets
  134. @project.reload
  135. assert_equal NUM_REV, @repository.changesets.count
  136. [
  137. "tag00.lightweight",
  138. "tag01.annotated",
  139. ].each do |t1|
  140. get :show, :id => PRJ_ID, :rev => t1
  141. assert_response :success
  142. assert_select 'table.entries tbody tr'
  143. assert_select 'table.changesets tbody tr'
  144. end
  145. end
  146. def test_browse_directory
  147. assert_equal 0, @repository.changesets.count
  148. @repository.fetch_changesets
  149. @project.reload
  150. assert_equal NUM_REV, @repository.changesets.count
  151. get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param]
  152. assert_response :success
  153. assert_select 'table.entries tbody' do
  154. assert_select 'tr', 1
  155. assert_select 'tr.file td.filename_no_report a', :text => 'edit.png'
  156. end
  157. assert_select 'table.changesets tbody tr'
  158. end
  159. def test_browse_at_given_revision
  160. assert_equal 0, @repository.changesets.count
  161. @repository.fetch_changesets
  162. @project.reload
  163. assert_equal NUM_REV, @repository.changesets.count
  164. get :show, :id => PRJ_ID, :path => repository_path_hash(['images'])[:param],
  165. :rev => '7234cb2750b63f47bff735edc50a1c0a433c2518'
  166. assert_response :success
  167. assert_select 'table.entries tbody' do
  168. assert_select 'tr', 1
  169. assert_select 'tr.file td.filename_no_report a', :text => 'delete.png'
  170. end
  171. end
  172. def test_changes
  173. get :changes, :id => PRJ_ID,
  174. :path => repository_path_hash(['images', 'edit.png'])[:param]
  175. assert_response :success
  176. assert_select 'h2', :text => /edit.png/
  177. end
  178. def test_entry_show
  179. get :entry, :id => PRJ_ID,
  180. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
  181. assert_response :success
  182. # Line 11
  183. assert_select 'tr#L11 td.line-code', :text => /WITHOUT ANY WARRANTY/
  184. end
  185. def test_entry_show_latin_1
  186. if @ruby19_non_utf8_pass
  187. puts_ruby19_non_utf8_pass()
  188. elsif WINDOWS_PASS
  189. puts WINDOWS_SKIP_STR
  190. elsif JRUBY_SKIP
  191. puts JRUBY_SKIP_STR
  192. else
  193. with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
  194. ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
  195. get :entry, :id => PRJ_ID,
  196. :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
  197. :rev => r1
  198. assert_response :success
  199. assert_select 'tr#L1 td.line-code', :text => /test-#{CHAR_1_HEX}.txt/
  200. end
  201. end
  202. end
  203. end
  204. def test_entry_download
  205. get :entry, :id => PRJ_ID,
  206. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
  207. :format => 'raw'
  208. assert_response :success
  209. # File content
  210. assert @response.body.include?('WITHOUT ANY WARRANTY')
  211. end
  212. def test_directory_entry
  213. get :entry, :id => PRJ_ID,
  214. :path => repository_path_hash(['sources'])[:param]
  215. assert_response :success
  216. assert_select 'h2 a', :text => 'sources'
  217. assert_select 'table.entries tbody'
  218. end
  219. def test_diff
  220. assert_equal true, @repository.is_default
  221. assert @repository.identifier.blank?
  222. assert_equal 0, @repository.changesets.count
  223. @repository.fetch_changesets
  224. @project.reload
  225. assert_equal NUM_REV, @repository.changesets.count
  226. # Full diff of changeset 2f9c0091
  227. ['inline', 'sbs'].each do |dt|
  228. get :diff,
  229. :id => PRJ_ID,
  230. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
  231. :type => dt
  232. assert_response :success
  233. # Line 22 removed
  234. assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
  235. assert_select 'h2', :text => /2f9c0091/
  236. end
  237. end
  238. def test_diff_with_rev_and_path
  239. assert_equal 0, @repository.changesets.count
  240. @repository.fetch_changesets
  241. @project.reload
  242. assert_equal NUM_REV, @repository.changesets.count
  243. with_settings :diff_max_lines_displayed => 1000 do
  244. # Full diff of changeset 2f9c0091
  245. ['inline', 'sbs'].each do |dt|
  246. get :diff,
  247. :id => PRJ_ID,
  248. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
  249. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
  250. :type => dt
  251. assert_response :success
  252. # Line 22 removed
  253. assert_select 'th.line-num:contains(22) ~ td.diff_out', :text => /def remove/
  254. assert_select 'h2', :text => /2f9c0091/
  255. end
  256. end
  257. end
  258. def test_diff_truncated
  259. assert_equal 0, @repository.changesets.count
  260. @repository.fetch_changesets
  261. @project.reload
  262. assert_equal NUM_REV, @repository.changesets.count
  263. with_settings :diff_max_lines_displayed => 5 do
  264. # Truncated diff of changeset 2f9c0091
  265. with_cache do
  266. with_settings :default_language => 'en' do
  267. get :diff, :id => PRJ_ID, :type => 'inline',
  268. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
  269. assert_response :success
  270. assert @response.body.include?("... This diff was truncated")
  271. end
  272. with_settings :default_language => 'fr' do
  273. get :diff, :id => PRJ_ID, :type => 'inline',
  274. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
  275. assert_response :success
  276. assert ! @response.body.include?("... This diff was truncated")
  277. assert @response.body.include?("... Ce diff")
  278. end
  279. end
  280. end
  281. end
  282. def test_diff_two_revs
  283. assert_equal 0, @repository.changesets.count
  284. @repository.fetch_changesets
  285. @project.reload
  286. assert_equal NUM_REV, @repository.changesets.count
  287. ['inline', 'sbs'].each do |dt|
  288. get :diff,
  289. :id => PRJ_ID,
  290. :rev => '61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
  291. :rev_to => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
  292. :type => dt
  293. assert_response :success
  294. assert_select 'h2', :text => /2f9c0091:61b685fb/
  295. assert_select 'form[action=?]', '/projects/subproject1/repository/revisions/61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff'
  296. assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
  297. end
  298. end
  299. def test_diff_path_in_subrepo
  300. repo = Repository::Git.create(
  301. :project => @project,
  302. :url => REPOSITORY_PATH,
  303. :identifier => 'test-diff-path',
  304. :path_encoding => 'ISO-8859-1'
  305. )
  306. assert repo
  307. assert_equal false, repo.is_default
  308. assert_equal 'test-diff-path', repo.identifier
  309. get :diff,
  310. :id => PRJ_ID,
  311. :repository_id => 'test-diff-path',
  312. :rev => '61b685fbe55ab05b',
  313. :rev_to => '2f9c0091c754a91a',
  314. :type => 'inline'
  315. assert_response :success
  316. assert_select 'form[action=?]', '/projects/subproject1/repository/test-diff-path/revisions/61b685fbe55ab05b/diff'
  317. assert_select 'input#rev_to[type=hidden][name=rev_to][value=?]', '2f9c0091c754a91a'
  318. end
  319. def test_diff_latin_1
  320. if @ruby19_non_utf8_pass
  321. puts_ruby19_non_utf8_pass()
  322. else
  323. with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
  324. ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
  325. ['inline', 'sbs'].each do |dt|
  326. get :diff, :id => PRJ_ID, :rev => r1, :type => dt
  327. assert_response :success
  328. assert_select 'table' do
  329. assert_select 'thead th.filename', :text => /latin-1-dir\/test-#{CHAR_1_HEX}.txt/
  330. assert_select 'tbody td.diff_in', :text => /test-#{CHAR_1_HEX}.txt/
  331. end
  332. end
  333. end
  334. end
  335. end
  336. end
  337. def test_diff_should_show_filenames
  338. get :diff, :id => PRJ_ID, :rev => 'deff712f05a90d96edbd70facc47d944be5897e3', :type => 'inline'
  339. assert_response :success
  340. # modified file
  341. assert_select 'th.filename', :text => 'sources/watchers_controller.rb'
  342. # deleted file
  343. assert_select 'th.filename', :text => 'test.txt'
  344. end
  345. def test_save_diff_type
  346. user1 = User.find(1)
  347. user1.pref[:diff_type] = nil
  348. user1.preference.save
  349. user = User.find(1)
  350. assert_nil user.pref[:diff_type]
  351. @request.session[:user_id] = 1 # admin
  352. get :diff,
  353. :id => PRJ_ID,
  354. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
  355. assert_response :success
  356. user.reload
  357. assert_equal "inline", user.pref[:diff_type]
  358. get :diff,
  359. :id => PRJ_ID,
  360. :rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7',
  361. :type => 'sbs'
  362. assert_response :success
  363. user.reload
  364. assert_equal "sbs", user.pref[:diff_type]
  365. end
  366. def test_annotate
  367. get :annotate, :id => PRJ_ID,
  368. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
  369. assert_response :success
  370. # Line 23, changeset 2f9c0091
  371. assert_select 'tr' do
  372. assert_select 'th.line-num', :text => '23'
  373. assert_select 'td.revision', :text => /2f9c0091/
  374. assert_select 'td.author', :text => 'jsmith'
  375. assert_select 'td', :text => /remove_watcher/
  376. end
  377. end
  378. def test_annotate_at_given_revision
  379. assert_equal 0, @repository.changesets.count
  380. @repository.fetch_changesets
  381. @project.reload
  382. assert_equal NUM_REV, @repository.changesets.count
  383. get :annotate, :id => PRJ_ID, :rev => 'deff7',
  384. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param]
  385. assert_response :success
  386. assert_select 'h2', :text => /@ deff712f/
  387. end
  388. def test_annotate_binary_file
  389. with_settings :default_language => 'en' do
  390. get :annotate, :id => PRJ_ID,
  391. :path => repository_path_hash(['images', 'edit.png'])[:param]
  392. assert_response :success
  393. assert_select 'p#errorExplanation', :text => /cannot be annotated/
  394. end
  395. end
  396. def test_annotate_error_when_too_big
  397. with_settings :file_max_size_displayed => 1 do
  398. get :annotate, :id => PRJ_ID,
  399. :path => repository_path_hash(['sources', 'watchers_controller.rb'])[:param],
  400. :rev => 'deff712f'
  401. assert_response :success
  402. assert_select 'p#errorExplanation', :text => /exceeds the maximum text file size/
  403. get :annotate, :id => PRJ_ID,
  404. :path => repository_path_hash(['README'])[:param],
  405. :rev => '7234cb2'
  406. assert_response :success
  407. end
  408. end
  409. def test_annotate_latin_1
  410. if @ruby19_non_utf8_pass
  411. puts_ruby19_non_utf8_pass()
  412. elsif WINDOWS_PASS
  413. puts WINDOWS_SKIP_STR
  414. elsif JRUBY_SKIP
  415. puts JRUBY_SKIP_STR
  416. else
  417. with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
  418. ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
  419. get :annotate, :id => PRJ_ID,
  420. :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
  421. :rev => r1
  422. assert_select "th.line-num", :text => '1' do
  423. assert_select "+ td.revision" do
  424. assert_select "a", :text => '57ca437c'
  425. assert_select "+ td.author", :text => "jsmith" do
  426. assert_select "+ td",
  427. :text => "test-#{CHAR_1_HEX}.txt"
  428. end
  429. end
  430. end
  431. end
  432. end
  433. end
  434. end
  435. def test_annotate_latin_1_author
  436. ['83ca5fd546063a3c7dc2e568ba3355661a9e2b2c', '83ca5fd546063a'].each do |r1|
  437. get :annotate, :id => PRJ_ID,
  438. :path => repository_path_hash([" filename with a leading space.txt "])[:param],
  439. :rev => r1
  440. assert_select "th.line-num", :text => '1' do
  441. assert_select "+ td.revision" do
  442. assert_select "a", :text => '83ca5fd5'
  443. assert_select "+ td.author", :text => FELIX_HEX do
  444. assert_select "+ td",
  445. :text => "And this is a file with a leading and trailing space..."
  446. end
  447. end
  448. end
  449. end
  450. end
  451. def test_revisions
  452. assert_equal 0, @repository.changesets.count
  453. @repository.fetch_changesets
  454. @project.reload
  455. assert_equal NUM_REV, @repository.changesets.count
  456. get :revisions, :id => PRJ_ID
  457. assert_select 'form[method=get][action=?]', '/projects/subproject1/repository/revision'
  458. end
  459. def test_revision
  460. assert_equal 0, @repository.changesets.count
  461. @repository.fetch_changesets
  462. @project.reload
  463. assert_equal NUM_REV, @repository.changesets.count
  464. ['61b685fbe55ab05b5ac68402d5720c1a6ac973d1', '61b685f'].each do |r|
  465. get :revision, :id => PRJ_ID, :rev => r
  466. assert_response :success
  467. end
  468. end
  469. def test_empty_revision
  470. assert_equal 0, @repository.changesets.count
  471. @repository.fetch_changesets
  472. @project.reload
  473. assert_equal NUM_REV, @repository.changesets.count
  474. ['', ' ', nil].each do |r|
  475. get :revision, :id => PRJ_ID, :rev => r
  476. assert_response 404
  477. assert_select_error /was not found/
  478. end
  479. end
  480. def test_destroy_valid_repository
  481. @request.session[:user_id] = 1 # admin
  482. assert_equal 0, @repository.changesets.count
  483. @repository.fetch_changesets
  484. @project.reload
  485. assert_equal NUM_REV, @repository.changesets.count
  486. assert_difference 'Repository.count', -1 do
  487. delete :destroy, :id => @repository.id
  488. end
  489. assert_response 302
  490. @project.reload
  491. assert_nil @project.repository
  492. end
  493. def test_destroy_invalid_repository
  494. @request.session[:user_id] = 1 # admin
  495. @project.repository.destroy
  496. @repository = Repository::Git.create!(
  497. :project => @project,
  498. :url => "/invalid",
  499. :path_encoding => 'ISO-8859-1'
  500. )
  501. @repository.fetch_changesets
  502. @repository.reload
  503. assert_equal 0, @repository.changesets.count
  504. assert_difference 'Repository.count', -1 do
  505. delete :destroy, :id => @repository.id
  506. end
  507. assert_response 302
  508. @project.reload
  509. assert_nil @project.repository
  510. end
  511. private
  512. def puts_ruby19_non_utf8_pass
  513. puts "TODO: This test fails " +
  514. "when Encoding.default_external is not UTF-8. " +
  515. "Current value is '#{Encoding.default_external.to_s}'"
  516. end
  517. else
  518. puts "Git test repository NOT FOUND. Skipping functional tests !!!"
  519. def test_fake; assert true end
  520. end
  521. private
  522. def with_cache(&block)
  523. before = ActionController::Base.perform_caching
  524. ActionController::Base.perform_caching = true
  525. block.call
  526. ActionController::Base.perform_caching = before
  527. end
  528. end