PageRenderTime 38ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/controllers/projects/merge_requests_controller_spec.rb

https://gitlab.com/matt.wilkinson/gitlab-ce
Ruby | 414 lines | 358 code | 56 blank | 0 comment | 0 complexity | 4ac5cfeb6b231953634a459fe02fbb59 MD5 | raw file
  1. require 'spec_helper'
  2. describe Projects::MergeRequestsController do
  3. let(:project) { create(:project) }
  4. let(:user) { create(:user) }
  5. let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
  6. before do
  7. sign_in(user)
  8. project.team << [user, :master]
  9. end
  10. describe '#new' do
  11. context 'merge request that removes a submodule' do
  12. render_views
  13. let(:fork_project) { create(:forked_project_with_submodules) }
  14. before do
  15. fork_project.team << [user, :master]
  16. end
  17. it 'renders it' do
  18. get :new,
  19. namespace_id: fork_project.namespace.to_param,
  20. project_id: fork_project.to_param,
  21. merge_request: {
  22. source_branch: 'remove-submodule',
  23. target_branch: 'master'
  24. }
  25. expect(response).to be_success
  26. end
  27. end
  28. end
  29. describe "#show" do
  30. shared_examples "export merge as" do |format|
  31. it "should generally work" do
  32. get(:show,
  33. namespace_id: project.namespace.to_param,
  34. project_id: project.to_param,
  35. id: merge_request.iid,
  36. format: format)
  37. expect(response).to be_success
  38. end
  39. it "should generate it" do
  40. expect_any_instance_of(MergeRequest).to receive(:"to_#{format}")
  41. get(:show,
  42. namespace_id: project.namespace.to_param,
  43. project_id: project.to_param,
  44. id: merge_request.iid,
  45. format: format)
  46. end
  47. it "should render it" do
  48. get(:show,
  49. namespace_id: project.namespace.to_param,
  50. project_id: project.to_param,
  51. id: merge_request.iid,
  52. format: format)
  53. expect(response.body).to eq(merge_request.send(:"to_#{format}").to_s)
  54. end
  55. it "should not escape Html" do
  56. allow_any_instance_of(MergeRequest).to receive(:"to_#{format}").
  57. and_return('HTML entities &<>" ')
  58. get(:show,
  59. namespace_id: project.namespace.to_param,
  60. project_id: project.to_param,
  61. id: merge_request.iid,
  62. format: format)
  63. expect(response.body).not_to include('&amp;')
  64. expect(response.body).not_to include('&gt;')
  65. expect(response.body).not_to include('&lt;')
  66. expect(response.body).not_to include('&quot;')
  67. end
  68. end
  69. describe "as diff" do
  70. it "triggers workhorse to serve the request" do
  71. get(:show,
  72. namespace_id: project.namespace.to_param,
  73. project_id: project.to_param,
  74. id: merge_request.iid,
  75. format: :diff)
  76. expect(response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-diff:")
  77. end
  78. end
  79. describe "as patch" do
  80. include_examples "export merge as", :patch
  81. let(:format) { :patch }
  82. it "should really be a git email patch with commit" do
  83. get(:show,
  84. namespace_id: project.namespace.to_param,
  85. project_id: project.to_param,
  86. id: merge_request.iid, format: format)
  87. expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}")
  88. end
  89. it "should contain git diffs" do
  90. get(:show,
  91. namespace_id: project.namespace.to_param,
  92. project_id: project.to_param,
  93. id: merge_request.iid,
  94. format: format)
  95. expect(response.body).to match(/^diff --git/)
  96. end
  97. end
  98. end
  99. describe 'GET #index' do
  100. def get_merge_requests
  101. get :index,
  102. namespace_id: project.namespace.to_param,
  103. project_id: project.to_param,
  104. state: 'opened'
  105. end
  106. context 'when filtering by opened state' do
  107. context 'with opened merge requests' do
  108. it 'should list those merge requests' do
  109. get_merge_requests
  110. expect(assigns(:merge_requests)).to include(merge_request)
  111. end
  112. end
  113. context 'with reopened merge requests' do
  114. before do
  115. merge_request.close!
  116. merge_request.reopen!
  117. end
  118. it 'should list those merge requests' do
  119. get_merge_requests
  120. expect(assigns(:merge_requests)).to include(merge_request)
  121. end
  122. end
  123. end
  124. end
  125. describe 'PUT #update' do
  126. context 'there is no source project' do
  127. let(:project) { create(:project) }
  128. let(:fork_project) { create(:forked_project_with_submodules) }
  129. let(:merge_request) { create(:merge_request, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
  130. before do
  131. fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
  132. fork_project.save
  133. merge_request.reload
  134. fork_project.destroy
  135. end
  136. it 'closes MR without errors' do
  137. post :update,
  138. namespace_id: project.namespace.path,
  139. project_id: project.path,
  140. id: merge_request.iid,
  141. merge_request: {
  142. state_event: 'close'
  143. }
  144. expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request])
  145. expect(merge_request.reload.closed?).to be_truthy
  146. end
  147. end
  148. end
  149. describe 'POST #merge' do
  150. let(:base_params) do
  151. {
  152. namespace_id: project.namespace.path,
  153. project_id: project.path,
  154. id: merge_request.iid,
  155. format: 'raw'
  156. }
  157. end
  158. context 'when the user does not have access' do
  159. before do
  160. project.team.truncate
  161. project.team << [user, :reporter]
  162. post :merge, base_params
  163. end
  164. it 'returns not found' do
  165. expect(response).to be_not_found
  166. end
  167. end
  168. context 'when the merge request is not mergeable' do
  169. before do
  170. merge_request.update_attributes(title: "WIP: #{merge_request.title}")
  171. post :merge, base_params
  172. end
  173. it 'returns :failed' do
  174. expect(assigns(:status)).to eq(:failed)
  175. end
  176. end
  177. context 'when the sha parameter does not match the source SHA' do
  178. before { post :merge, base_params.merge(sha: 'foo') }
  179. it 'returns :sha_mismatch' do
  180. expect(assigns(:status)).to eq(:sha_mismatch)
  181. end
  182. end
  183. context 'when the sha parameter matches the source SHA' do
  184. def merge_with_sha
  185. post :merge, base_params.merge(sha: merge_request.source_sha)
  186. end
  187. it 'returns :success' do
  188. merge_with_sha
  189. expect(assigns(:status)).to eq(:success)
  190. end
  191. it 'starts the merge immediately' do
  192. expect(MergeWorker).to receive(:perform_async).with(merge_request.id, anything, anything)
  193. merge_with_sha
  194. end
  195. context 'when merge_when_build_succeeds is passed' do
  196. def merge_when_build_succeeds
  197. post :merge, base_params.merge(sha: merge_request.source_sha, merge_when_build_succeeds: '1')
  198. end
  199. before do
  200. create(:ci_empty_pipeline, project: project, sha: merge_request.source_sha, ref: merge_request.source_branch)
  201. end
  202. it 'returns :merge_when_build_succeeds' do
  203. merge_when_build_succeeds
  204. expect(assigns(:status)).to eq(:merge_when_build_succeeds)
  205. end
  206. it 'sets the MR to merge when the build succeeds' do
  207. service = double(:merge_when_build_succeeds_service)
  208. expect(MergeRequests::MergeWhenBuildSucceedsService).to receive(:new).with(project, anything, anything).and_return(service)
  209. expect(service).to receive(:execute).with(merge_request)
  210. merge_when_build_succeeds
  211. end
  212. end
  213. end
  214. end
  215. describe "DELETE #destroy" do
  216. it "denies access to users unless they're admin or project owner" do
  217. delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid
  218. expect(response.status).to eq(404)
  219. end
  220. context "when the user is owner" do
  221. let(:owner) { create(:user) }
  222. let(:namespace) { create(:namespace, owner: owner) }
  223. let(:project) { create(:project, namespace: namespace) }
  224. before { sign_in owner }
  225. it "deletes the merge request" do
  226. delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid
  227. expect(response.status).to eq(302)
  228. expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./).now
  229. end
  230. end
  231. end
  232. describe 'GET diffs' do
  233. def go(format: 'html')
  234. get :diffs,
  235. namespace_id: project.namespace.to_param,
  236. project_id: project.to_param,
  237. id: merge_request.iid,
  238. format: format
  239. end
  240. context 'as html' do
  241. it 'renders the diff template' do
  242. go
  243. expect(response).to render_template('diffs')
  244. end
  245. end
  246. context 'as json' do
  247. it 'renders the diffs template to a string' do
  248. go format: 'json'
  249. expect(response).to render_template('projects/merge_requests/show/_diffs')
  250. expect(JSON.parse(response.body)).to have_key('html')
  251. end
  252. end
  253. context 'with forked projects with submodules' do
  254. render_views
  255. let(:project) { create(:project) }
  256. let(:fork_project) { create(:forked_project_with_submodules) }
  257. let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
  258. before do
  259. fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
  260. fork_project.save
  261. merge_request.reload
  262. end
  263. it 'renders' do
  264. go format: 'json'
  265. expect(response).to be_success
  266. expect(response.body).to have_content('Subproject commit')
  267. end
  268. end
  269. end
  270. describe 'GET diffs with ignore_whitespace_change' do
  271. def go(format: 'html')
  272. get :diffs,
  273. namespace_id: project.namespace.to_param,
  274. project_id: project.to_param,
  275. id: merge_request.iid,
  276. format: format,
  277. w: 1
  278. end
  279. context 'as html' do
  280. it 'renders the diff template' do
  281. go
  282. expect(response).to render_template('diffs')
  283. end
  284. end
  285. context 'as json' do
  286. it 'renders the diffs template to a string' do
  287. go format: 'json'
  288. expect(response).to render_template('projects/merge_requests/show/_diffs')
  289. expect(JSON.parse(response.body)).to have_key('html')
  290. end
  291. end
  292. end
  293. describe 'GET diffs with view' do
  294. def go(extra_params = {})
  295. params = {
  296. namespace_id: project.namespace.to_param,
  297. project_id: project.to_param,
  298. id: merge_request.iid
  299. }
  300. get :diffs, params.merge(extra_params)
  301. end
  302. it 'saves the preferred diff view in a cookie' do
  303. go view: 'parallel'
  304. expect(response.cookies['diff_view']).to eq('parallel')
  305. end
  306. end
  307. describe 'GET commits' do
  308. def go(format: 'html')
  309. get :commits,
  310. namespace_id: project.namespace.to_param,
  311. project_id: project.to_param,
  312. id: merge_request.iid,
  313. format: format
  314. end
  315. context 'as html' do
  316. it 'renders the show template' do
  317. go
  318. expect(response).to render_template('show')
  319. end
  320. end
  321. context 'as json' do
  322. it 'renders the commits template to a string' do
  323. go format: 'json'
  324. expect(response).to render_template('projects/merge_requests/show/_commits')
  325. expect(JSON.parse(response.body)).to have_key('html')
  326. end
  327. end
  328. end
  329. end