PageRenderTime 87ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/ee/spec/requests/api/status_checks_spec.rb

https://gitlab.com/realsatomic/gitlab
Ruby | 408 lines | 312 code | 95 blank | 1 comment | 2 complexity | c7c87343e292538c4200373673f36fbd MD5 | raw file
  1. # frozen_string_literal: true
  2. require 'spec_helper'
  3. RSpec.describe API::StatusChecks do
  4. include AccessMatchersForRequest
  5. using RSpec::Parameterized::TableSyntax
  6. let_it_be(:project) { create(:project, :repository) }
  7. let_it_be(:another_project) { create(:project, :repository, :public) }
  8. let_it_be(:rule) { create(:external_status_check, project: project) }
  9. let_it_be(:rule_2) { create(:external_status_check, project: project) }
  10. let_it_be(:user) { create(:user) }
  11. let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
  12. let(:single_object_url) { "/projects/#{project.id}/external_status_checks/#{rule.id}" }
  13. let(:collection_url) { "/projects/#{project.id}/external_status_checks" }
  14. let(:sha) { merge_request.source_branch_sha }
  15. let(:status) { '' }
  16. subject { get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/status_checks", user), params: { external_status_check_id: rule.id, sha: sha } }
  17. describe 'GET :id/merge_requests/:merge_request_iid/status_checks' do
  18. context 'when current_user has access' do
  19. before do
  20. stub_licensed_features(external_status_checks: true)
  21. project.add_user(user, :maintainer)
  22. end
  23. context 'when merge request has received status check responses' do
  24. let!(:non_applicable_check) { create(:external_status_check, project: project, protected_branches: [create(:protected_branch, name: 'different-branch', project: project)]) }
  25. let!(:branch_specific_check) { create(:external_status_check, project: project, protected_branches: [create(:protected_branch, name: merge_request.target_branch, project: project)]) }
  26. let!(:status_check_response) { create(:status_check_response, external_status_check: rule, merge_request: merge_request, sha: sha) }
  27. it 'returns a 200' do
  28. subject
  29. expect(response).to have_gitlab_http_status(:success)
  30. end
  31. it 'returns the total number of status checks for the MRs project' do
  32. subject
  33. expect(json_response.size).to eq(3)
  34. end
  35. it 'has the correct status values' do
  36. subject
  37. expect(json_response[0]["status"]).to eq('passed')
  38. expect(json_response[1]["status"]).to eq('pending')
  39. expect(json_response[2]["status"]).to eq('pending')
  40. end
  41. context 'when status_checks_add_status_field is disabled' do
  42. before do
  43. stub_feature_flags(status_checks_add_status_field: false)
  44. end
  45. it 'has the correct status values' do
  46. subject
  47. expect(json_response[0]["status"]).to eq('approved')
  48. expect(json_response[1]["status"]).to eq('pending')
  49. expect(json_response[2]["status"]).to eq('pending')
  50. end
  51. end
  52. end
  53. end
  54. end
  55. describe 'POST :id/:merge_requests/:merge_request_iid/status_check_responses' do
  56. subject { post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/status_check_responses", user), params: { external_status_check_id: rule.id, sha: sha, status: status } }
  57. let(:status) { 'passed' }
  58. context 'permissions' do
  59. using RSpec::Parameterized::TableSyntax
  60. where(:user_permissions, :applies_to_target_project, :expected_status) do
  61. :maintainer | true | :created
  62. :maintainer | false | :not_found
  63. :developer | true | :created
  64. :developer | false | :not_found
  65. :guest | true | :forbidden
  66. :guest | false | :not_found
  67. end
  68. with_them do
  69. before do
  70. stub_licensed_features(external_status_checks: true)
  71. if applies_to_target_project
  72. project.add_user(user, user_permissions)
  73. else
  74. another_project.add_user(user, user_permissions)
  75. end
  76. end
  77. it 'returns the correct status' do
  78. subject
  79. expect(response).to have_gitlab_http_status(expected_status)
  80. end
  81. end
  82. end
  83. context 'when user has access' do
  84. before do
  85. stub_licensed_features(external_status_checks: true)
  86. project.add_user(user, :maintainer) if user
  87. end
  88. context 'when status_checks_add_status_field flag is disabled' do
  89. before do
  90. stub_feature_flags(status_checks_add_status_field: false)
  91. end
  92. context 'status is failed' do
  93. let(:status) { 'failed' }
  94. it 'is overridden to passed' do
  95. subject
  96. expect(MergeRequests::StatusCheckResponse.last.status).to eq("passed")
  97. end
  98. end
  99. end
  100. context 'when external status check ID does not belong to the requested project' do
  101. let_it_be(:rule) { create(:external_status_check) }
  102. it 'returns a not found status' do
  103. subject
  104. expect(response).to have_gitlab_http_status(:not_found)
  105. end
  106. end
  107. context 'when sha is not the source branch HEAD' do
  108. let(:sha) { 'notarealsha' }
  109. it 'does not create a new approval' do
  110. expect { subject }.not_to change { MergeRequests::StatusCheckResponse.count }
  111. end
  112. it 'returns a conflict error' do
  113. subject
  114. expect(response).to have_gitlab_http_status(:conflict)
  115. end
  116. end
  117. context 'when user is not authenticated' do
  118. let(:user) { nil }
  119. it 'returns an unauthorized status' do
  120. subject
  121. expect(response).to have_gitlab_http_status(:unauthorized)
  122. end
  123. end
  124. end
  125. end
  126. describe 'DELETE projects/:id/external_status_checks/:check_id' do
  127. before do
  128. stub_licensed_features(external_status_checks: true)
  129. end
  130. it 'deletes the specified rule' do
  131. expect do
  132. delete api(single_object_url, project.first_owner)
  133. end.to change { MergeRequests::ExternalStatusCheck.count }.by(-1)
  134. end
  135. context 'when feature is disabled, unlicensed or user has permission' do
  136. where(:licensed, :project_owner, :status) do
  137. false | false | :not_found
  138. false | true | :unauthorized
  139. true | false | :not_found
  140. true | true | :success
  141. end
  142. with_them do
  143. before do
  144. stub_licensed_features(external_status_checks: licensed)
  145. end
  146. it 'returns the correct status code' do
  147. delete api(single_object_url, (project_owner ? project.first_owner : build(:user)))
  148. expect(response).to have_gitlab_http_status(status)
  149. end
  150. end
  151. end
  152. end
  153. describe 'POST projects/:id/external_status_checks' do
  154. context 'successfully creating new external approval rule' do
  155. before do
  156. stub_licensed_features(external_status_checks: true)
  157. end
  158. subject do
  159. post api("/projects/#{project.id}/external_status_checks", project.first_owner), params: attributes_for(:external_status_check)
  160. end
  161. it 'creates a new external approval rule' do
  162. expect { subject }.to change { MergeRequests::ExternalStatusCheck.count }.by(1)
  163. end
  164. context 'with protected branches' do
  165. let_it_be(:protected_branch) { create(:protected_branch, project: project) }
  166. let(:params) do
  167. { name: 'New rule', external_url: 'https://gitlab.com/test/example.json', protected_branch_ids: protected_branch.id }
  168. end
  169. subject do
  170. post api("/projects/#{project.id}/external_status_checks", project.first_owner), params: params
  171. end
  172. it 'returns expected status code' do
  173. subject
  174. expect(response).to have_gitlab_http_status(:created)
  175. end
  176. it 'creates protected branch records' do
  177. subject
  178. expect(MergeRequests::ExternalStatusCheck.last.protected_branches.count).to eq 1
  179. end
  180. it 'responds with expected JSON' do
  181. subject
  182. expect(json_response['id']).not_to be_nil
  183. expect(json_response['name']).to eq('New rule')
  184. expect(json_response['external_url']).to eq('https://gitlab.com/test/example.json')
  185. expect(json_response['protected_branches'].size).to eq(1)
  186. end
  187. end
  188. end
  189. context 'when feature is disabled, unlicensed or user has permission' do
  190. where(:licensed, :project_owner, :status) do
  191. false | false | :not_found
  192. false | true | :unauthorized
  193. true | false | :not_found
  194. true | true | :created
  195. end
  196. with_them do
  197. before do
  198. stub_licensed_features(external_status_checks: licensed)
  199. end
  200. it 'returns the correct status code' do
  201. post api("/projects/#{project.id}/external_status_checks", (project_owner ? project.owner : build(:user))), params: attributes_for(:external_status_check)
  202. expect(response).to have_gitlab_http_status(status)
  203. end
  204. end
  205. end
  206. end
  207. describe 'GET projects/:id/external_status_checks' do
  208. let_it_be(:protected_branches) { create_list(:protected_branch, 3, project: project) }
  209. before_all do
  210. create(:external_status_check) # Creating an orphaned rule to make sure project scoping works as expected
  211. end
  212. before do
  213. stub_licensed_features(external_status_checks: true)
  214. end
  215. it 'responds with expected JSON', :aggregate_failures do
  216. get api(collection_url, project.first_owner)
  217. expect(json_response.size).to eq(2)
  218. expect(json_response.map { |r| r['name'] }).to contain_exactly('rule 1', 'rule 2')
  219. end
  220. it 'paginates correctly' do
  221. get api(collection_url, project.first_owner), params: { per_page: 1 }
  222. expect_paginated_array_response([rule.id])
  223. end
  224. context 'when feature is disabled, unlicensed or user has permission' do
  225. where(:licensed, :project_owner, :status) do
  226. false | false | :not_found
  227. false | true | :unauthorized
  228. true | false | :not_found
  229. true | true | :success
  230. end
  231. with_them do
  232. before do
  233. stub_licensed_features(external_status_checks: licensed)
  234. end
  235. it 'returns the correct status code' do
  236. get api(collection_url, (project_owner ? project.first_owner : build(:user)))
  237. expect(response).to have_gitlab_http_status(status)
  238. end
  239. end
  240. end
  241. end
  242. describe 'PUT projects/:id/external_status_checks/:check_id' do
  243. let(:params) { { external_url: 'http://newvalue.com', name: 'new name' } }
  244. context 'successfully updating external approval rule' do
  245. before do
  246. stub_licensed_features(external_status_checks: true)
  247. end
  248. subject do
  249. put api(single_object_url, project.first_owner), params: params
  250. end
  251. it 'updates an approval rule' do
  252. expect { subject }.to change { rule.reload.external_url }.to eq('http://newvalue.com')
  253. end
  254. it 'responds with correct http status' do
  255. subject
  256. expect(response).to have_gitlab_http_status(:success)
  257. end
  258. context 'when referencing a protected branch outside of the project' do
  259. let_it_be(:protected_branch) { create(:protected_branch) }
  260. let(:params) do
  261. { name: 'New rule', external_url: 'https://gitlab.com/test/example.json', protected_branch_ids: protected_branch.id }
  262. end
  263. subject do
  264. put api(single_object_url, project.first_owner), params: params
  265. end
  266. it 'is invalid' do
  267. subject
  268. expect(response).to have_gitlab_http_status(:unprocessable_entity)
  269. end
  270. end
  271. context 'with protected branches' do
  272. let_it_be(:protected_branch) { create(:protected_branch, project: project) }
  273. let(:params) do
  274. { name: 'New rule', external_url: 'https://gitlab.com/test/example.json', protected_branch_ids: protected_branch.id }
  275. end
  276. subject do
  277. put api(single_object_url, project.first_owner), params: params
  278. end
  279. it 'returns expected status code' do
  280. subject
  281. expect(response).to have_gitlab_http_status(:success)
  282. end
  283. it 'creates protected branch records' do
  284. expect { subject }.to change { MergeRequests::ExternalStatusCheck.last.protected_branches }
  285. end
  286. it 'responds with expected JSON', :aggregate_failures do
  287. subject
  288. expect(json_response['id']).not_to be_nil
  289. expect(json_response['name']).to eq('New rule')
  290. expect(json_response['external_url']).to eq('https://gitlab.com/test/example.json')
  291. expect(json_response['protected_branches'].size).to eq(1)
  292. end
  293. end
  294. end
  295. context 'when feature is disabled, unlicensed or user has permission' do
  296. where(:licensed, :project_owner, :status) do
  297. false | false | :not_found
  298. false | true | :unauthorized
  299. true | false | :not_found
  300. true | true | :success
  301. end
  302. with_them do
  303. before do
  304. stub_licensed_features(external_status_checks: licensed)
  305. end
  306. it 'returns the correct status code' do
  307. put api(single_object_url, (project_owner ? project.first_owner : build(:user))), params: attributes_for(:external_status_check)
  308. expect(response).to have_gitlab_http_status(status)
  309. end
  310. end
  311. end
  312. end
  313. end