merge_requests_spec.rb 28.6 KB
Newer Older
V
Valeriy Sizov 已提交
1 2
require "spec_helper"

3
describe API::MergeRequests, api: true  do
V
Valeriy Sizov 已提交
4
  include ApiHelpers
Z
Zeger-Jan van de Weg 已提交
5 6 7
  let(:base_time)   { Time.now }
  let(:user)        { create(:user) }
  let(:admin)       { create(:user, :admin) }
8
  let(:non_member)  { create(:user) }
Z
Zeger-Jan van de Weg 已提交
9
  let!(:project)    { create(:project, creator_id: user.id, namespace: user.namespace) }
S
Stan Hu 已提交
10
  let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
G
Gabriel Mazetto 已提交
11
  let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
12
  let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') }
Z
Zeger-Jan van de Weg 已提交
13 14 15
  let!(:note)       { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
  let!(:note2)      { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
  let(:milestone)   { create(:milestone, title: '1.0.0', project: project) }
16 17

  before do
18
    project.team << [user, :reporter]
19
  end
V
Valeriy Sizov 已提交
20 21 22

  describe "GET /projects/:id/merge_requests" do
    context "when unauthenticated" do
23
      it "returns authentication error" do
H
Hiroyuki Sato 已提交
24
        get api("/projects/#{project.id}/merge_requests")
Z
Z.J. van de Weg 已提交
25
        expect(response).to have_http_status(401)
V
Valeriy Sizov 已提交
26 27 28 29
      end
    end

    context "when authenticated" do
30
      it "returns an array of all merge_requests" do
H
Hiroyuki Sato 已提交
31
        get api("/projects/#{project.id}/merge_requests", user)
Z
Z.J. van de Weg 已提交
32
        expect(response).to have_http_status(200)
33 34 35
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(3)
        expect(json_response.last['title']).to eq(merge_request.title)
36
        expect(json_response.last).to have_key('web_url')
37 38 39 40 41 42 43
        expect(json_response.last['sha']).to eq(merge_request.diff_head_sha)
        expect(json_response.last['merge_commit_sha']).to be_nil
        expect(json_response.last['merge_commit_sha']).to eq(merge_request.merge_commit_sha)
        expect(json_response.first['title']).to eq(merge_request_merged.title)
        expect(json_response.first['sha']).to eq(merge_request_merged.diff_head_sha)
        expect(json_response.first['merge_commit_sha']).not_to be_nil
        expect(json_response.first['merge_commit_sha']).to eq(merge_request_merged.merge_commit_sha)
V
Valeriy Sizov 已提交
44
      end
45

46
      it "returns an array of all merge_requests" do
47
        get api("/projects/#{project.id}/merge_requests?state", user)
Z
Z.J. van de Weg 已提交
48
        expect(response).to have_http_status(200)
49 50 51
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(3)
        expect(json_response.last['title']).to eq(merge_request.title)
52
      end
53

54
      it "returns an array of open merge_requests" do
55
        get api("/projects/#{project.id}/merge_requests?state=opened", user)
Z
Z.J. van de Weg 已提交
56
        expect(response).to have_http_status(200)
57 58 59
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(1)
        expect(json_response.last['title']).to eq(merge_request.title)
60
      end
61

62
      it "returns an array of closed merge_requests" do
63
        get api("/projects/#{project.id}/merge_requests?state=closed", user)
Z
Z.J. van de Weg 已提交
64
        expect(response).to have_http_status(200)
65
        expect(json_response).to be_an Array
66 67
        expect(json_response.length).to eq(1)
        expect(json_response.first['title']).to eq(merge_request_closed.title)
68
      end
69

70
      it "returns an array of merged merge_requests" do
71
        get api("/projects/#{project.id}/merge_requests?state=merged", user)
Z
Z.J. van de Weg 已提交
72
        expect(response).to have_http_status(200)
73 74 75
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(1)
        expect(json_response.first['title']).to eq(merge_request_merged.title)
76
      end
77 78 79 80 81 82 83

      context "with ordering" do
        before do
          @mr_later = mr_with_later_created_and_updated_at_time
          @mr_earlier = mr_with_earlier_created_and_updated_at_time
        end

84
        it "returns an array of merge_requests in ascending order" do
85
          get api("/projects/#{project.id}/merge_requests?sort=asc", user)
Z
Z.J. van de Weg 已提交
86
          expect(response).to have_http_status(200)
87 88
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(3)
S
Stan Hu 已提交
89 90
          response_dates = json_response.map{ |merge_request| merge_request['created_at'] }
          expect(response_dates).to eq(response_dates.sort)
91
        end
D
Dmitriy Zaporozhets 已提交
92

93
        it "returns an array of merge_requests in descending order" do
94
          get api("/projects/#{project.id}/merge_requests?sort=desc", user)
Z
Z.J. van de Weg 已提交
95
          expect(response).to have_http_status(200)
96 97
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(3)
S
Stan Hu 已提交
98 99
          response_dates = json_response.map{ |merge_request| merge_request['created_at'] }
          expect(response_dates).to eq(response_dates.sort.reverse)
100
        end
D
Dmitriy Zaporozhets 已提交
101

102
        it "returns an array of merge_requests ordered by updated_at" do
103
          get api("/projects/#{project.id}/merge_requests?order_by=updated_at", user)
Z
Z.J. van de Weg 已提交
104
          expect(response).to have_http_status(200)
105 106
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(3)
S
Stan Hu 已提交
107 108
          response_dates = json_response.map{ |merge_request| merge_request['updated_at'] }
          expect(response_dates).to eq(response_dates.sort.reverse)
109
        end
D
Dmitriy Zaporozhets 已提交
110

111
        it "returns an array of merge_requests ordered by created_at" do
S
Stan Hu 已提交
112
          get api("/projects/#{project.id}/merge_requests?order_by=created_at&sort=asc", user)
Z
Z.J. van de Weg 已提交
113
          expect(response).to have_http_status(200)
114 115
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(3)
S
Stan Hu 已提交
116 117
          response_dates = json_response.map{ |merge_request| merge_request['created_at'] }
          expect(response_dates).to eq(response_dates.sort)
118
        end
119
      end
V
Valeriy Sizov 已提交
120 121 122
    end
  end

123
  describe "GET /projects/:id/merge_requests/:merge_request_id" do
124 125 126
    it 'exposes known attributes' do
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)

Z
Z.J. van de Weg 已提交
127
      expect(response).to have_http_status(200)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
      expect(json_response['id']).to eq(merge_request.id)
      expect(json_response['iid']).to eq(merge_request.iid)
      expect(json_response['project_id']).to eq(merge_request.project.id)
      expect(json_response['title']).to eq(merge_request.title)
      expect(json_response['description']).to eq(merge_request.description)
      expect(json_response['state']).to eq(merge_request.state)
      expect(json_response['created_at']).to be_present
      expect(json_response['updated_at']).to be_present
      expect(json_response['labels']).to eq(merge_request.label_names)
      expect(json_response['milestone']).to be_nil
      expect(json_response['assignee']).to be_a Hash
      expect(json_response['author']).to be_a Hash
      expect(json_response['target_branch']).to eq(merge_request.target_branch)
      expect(json_response['source_branch']).to eq(merge_request.source_branch)
      expect(json_response['upvotes']).to eq(0)
      expect(json_response['downvotes']).to eq(0)
      expect(json_response['source_project_id']).to eq(merge_request.source_project.id)
      expect(json_response['target_project_id']).to eq(merge_request.target_project.id)
      expect(json_response['work_in_progress']).to be_falsy
      expect(json_response['merge_when_build_succeeds']).to be_falsy
      expect(json_response['merge_status']).to eq('can_be_merged')
149 150
      expect(json_response['should_close_merge_request']).to be_falsy
      expect(json_response['force_close_merge_request']).to be_falsy
151 152
    end

153
    it "returns merge_request" do
154
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
Z
Z.J. van de Weg 已提交
155
      expect(response).to have_http_status(200)
156 157
      expect(json_response['title']).to eq(merge_request.title)
      expect(json_response['iid']).to eq(merge_request.iid)
158
      expect(json_response['work_in_progress']).to eq(false)
159
      expect(json_response['merge_status']).to eq('can_be_merged')
160 161
      expect(json_response['should_close_merge_request']).to be_falsy
      expect(json_response['force_close_merge_request']).to be_falsy
V
Valeriy Sizov 已提交
162
    end
163

164
    it 'returns merge_request by iid' do
165 166
      url = "/projects/#{project.id}/merge_requests?iid=#{merge_request.iid}"
      get api(url, user)
167 168 169
      expect(response.status).to eq 200
      expect(json_response.first['title']).to eq merge_request.title
      expect(json_response.first['id']).to eq merge_request.id
170 171
    end

172 173 174 175 176 177 178 179 180 181
    it 'returns merge_request by iid array' do
      get api("/projects/#{project.id}/merge_requests", user), iid: [merge_request.iid, merge_request_closed.iid]

      expect(response).to have_http_status(200)
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(2)
      expect(json_response.first['title']).to eq merge_request_closed.title
      expect(json_response.first['id']).to eq merge_request_closed.id
    end

182
    it "returns a 404 error if merge_request_id not found" do
183
      get api("/projects/#{project.id}/merge_requests/999", user)
Z
Z.J. van de Weg 已提交
184
      expect(response).to have_http_status(404)
185
    end
186 187 188 189

    context 'Work in Progress' do
      let!(:merge_request_wip) { create(:merge_request, author: user, assignee: user, source_project: project, target_project: project, title: "WIP: Test", created_at: base_time + 1.second) }

190
      it "returns merge_request" do
191
        get api("/projects/#{project.id}/merge_requests/#{merge_request_wip.id}", user)
Z
Z.J. van de Weg 已提交
192
        expect(response).to have_http_status(200)
193 194 195
        expect(json_response['work_in_progress']).to eq(true)
      end
    end
V
Valeriy Sizov 已提交
196 197
  end

198
  describe 'GET /projects/:id/merge_requests/:merge_request_id/commits' do
V
Valery Sizov 已提交
199 200 201 202 203 204 205 206
    it 'returns a 200 when merge request is valid' do
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user)
      commit = merge_request.commits.first

      expect(response.status).to eq 200
      expect(json_response.size).to eq(merge_request.commits.size)
      expect(json_response.first['id']).to eq(commit.id)
      expect(json_response.first['title']).to eq(commit.title)
207 208 209
    end

    it 'returns a 404 when merge_request_id not found' do
210
      get api("/projects/#{project.id}/merge_requests/999/commits", user)
Z
Z.J. van de Weg 已提交
211
      expect(response).to have_http_status(404)
212 213 214
    end
  end

215
  describe 'GET /projects/:id/merge_requests/:merge_request_id/changes' do
216
    it 'returns the change information of the merge_request' do
217
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/changes", user)
218 219 220 221 222
      expect(response.status).to eq 200
      expect(json_response['changes'].size).to eq(merge_request.diffs.size)
    end

    it 'returns a 404 when merge_request_id not found' do
223
      get api("/projects/#{project.id}/merge_requests/999/changes", user)
Z
Z.J. van de Weg 已提交
224
      expect(response).to have_http_status(404)
225 226 227
    end
  end

V
Valeriy Sizov 已提交
228
  describe "POST /projects/:id/merge_requests" do
I
Izaak Alpert 已提交
229
    context 'between branches projects' do
230
      it "returns merge_request" do
H
Hiroyuki Sato 已提交
231
        post api("/projects/#{project.id}/merge_requests", user),
232
             title: 'Test merge_request',
233
             source_branch: 'feature_conflict',
234 235
             target_branch: 'master',
             author: user,
236 237
             labels: 'label, label2',
             milestone_id: milestone.id
Z
Z.J. van de Weg 已提交
238
        expect(response).to have_http_status(201)
239 240
        expect(json_response['title']).to eq('Test merge_request')
        expect(json_response['labels']).to eq(['label', 'label2'])
241
        expect(json_response['milestone']['id']).to eq(milestone.id)
I
Izaak Alpert 已提交
242
      end
243

244
      it "returns 422 when source_branch equals target_branch" do
H
Hiroyuki Sato 已提交
245
        post api("/projects/#{project.id}/merge_requests", user),
246
        title: "Test merge_request", source_branch: "master", target_branch: "master", author: user
Z
Z.J. van de Weg 已提交
247
        expect(response).to have_http_status(422)
I
Izaak Alpert 已提交
248
      end
249

250
      it "returns 400 when source_branch is missing" do
H
Hiroyuki Sato 已提交
251
        post api("/projects/#{project.id}/merge_requests", user),
252
        title: "Test merge_request", target_branch: "master", author: user
Z
Z.J. van de Weg 已提交
253
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
254
      end
255

256
      it "returns 400 when target_branch is missing" do
H
Hiroyuki Sato 已提交
257
        post api("/projects/#{project.id}/merge_requests", user),
258
        title: "Test merge_request", source_branch: "markdown", author: user
Z
Z.J. van de Weg 已提交
259
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
260 261
      end

262
      it "returns 400 when title is missing" do
H
Hiroyuki Sato 已提交
263
        post api("/projects/#{project.id}/merge_requests", user),
264
        target_branch: 'master', source_branch: 'markdown'
Z
Z.J. van de Weg 已提交
265
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
266
      end
267

268
      it 'allows special label names' do
269 270
        post api("/projects/#{project.id}/merge_requests", user),
             title: 'Test merge_request',
271
             source_branch: 'markdown',
272 273
             target_branch: 'master',
             author: user,
274 275 276 277 278 279 280
             labels: 'label, label?, label&foo, ?, &'
        expect(response.status).to eq(201)
        expect(json_response['labels']).to include 'label'
        expect(json_response['labels']).to include 'label?'
        expect(json_response['labels']).to include 'label&foo'
        expect(json_response['labels']).to include '?'
        expect(json_response['labels']).to include '&'
281
      end
J
jubianchi 已提交
282 283 284 285 286

      context 'with existing MR' do
        before do
          post api("/projects/#{project.id}/merge_requests", user),
               title: 'Test merge_request',
287
               source_branch: 'feature_conflict',
J
jubianchi 已提交
288 289 290 291 292
               target_branch: 'master',
               author: user
          @mr = MergeRequest.all.last
        end

293
        it 'returns 409 when MR already exists for source/target' do
J
jubianchi 已提交
294 295 296
          expect do
            post api("/projects/#{project.id}/merge_requests", user),
                 title: 'New test merge_request',
297
                 source_branch: 'feature_conflict',
J
jubianchi 已提交
298 299 300
                 target_branch: 'master',
                 author: user
          end.to change { MergeRequest.count }.by(0)
Z
Z.J. van de Weg 已提交
301
          expect(response).to have_http_status(409)
J
jubianchi 已提交
302 303
        end
      end
304
    end
305

I
Izaak Alpert 已提交
306
    context 'forked projects' do
D
Dmitriy Zaporozhets 已提交
307 308 309
      let!(:user2) { create(:user) }
      let!(:fork_project) { create(:project, forked_from_project: project,  namespace: user2.namespace, creator_id: user2.id) }
      let!(:unrelated_project) { create(:project,  namespace: create(:user).namespace, creator_id: user2.id) }
I
Izaak Alpert 已提交
310 311

      before :each do |each|
312
        fork_project.team << [user2, :reporter]
I
Izaak Alpert 已提交
313 314
      end

315
      it "returns merge_request" do
H
Hiroyuki Sato 已提交
316
        post api("/projects/#{fork_project.id}/merge_requests", user2),
317 318
          title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master",
          author: user2, target_project_id: project.id, description: 'Test description for Test merge_request'
Z
Z.J. van de Weg 已提交
319
        expect(response).to have_http_status(201)
320 321
        expect(json_response['title']).to eq('Test merge_request')
        expect(json_response['description']).to eq('Test description for Test merge_request')
I
Izaak Alpert 已提交
322 323
      end

324
      it "does not return 422 when source_branch equals target_branch" do
325 326 327
        expect(project.id).not_to eq(fork_project.id)
        expect(fork_project.forked?).to be_truthy
        expect(fork_project.forked_from_project).to eq(project)
H
Hiroyuki Sato 已提交
328
        post api("/projects/#{fork_project.id}/merge_requests", user2),
329
        title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id
Z
Z.J. van de Weg 已提交
330
        expect(response).to have_http_status(201)
331
        expect(json_response['title']).to eq('Test merge_request')
I
Izaak Alpert 已提交
332 333
      end

334
      it "returns 400 when source_branch is missing" do
H
Hiroyuki Sato 已提交
335
        post api("/projects/#{fork_project.id}/merge_requests", user2),
336
        title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
Z
Z.J. van de Weg 已提交
337
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
338 339
      end

340
      it "returns 400 when target_branch is missing" do
H
Hiroyuki Sato 已提交
341
        post api("/projects/#{fork_project.id}/merge_requests", user2),
342
        title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
Z
Z.J. van de Weg 已提交
343
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
344 345
      end

346
      it "returns 400 when title is missing" do
H
Hiroyuki Sato 已提交
347
        post api("/projects/#{fork_project.id}/merge_requests", user2),
348
        target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: project.id
Z
Z.J. van de Weg 已提交
349
        expect(response).to have_http_status(400)
I
Izaak Alpert 已提交
350 351
      end

J
jubianchi 已提交
352
      context 'when target_branch is specified' do
353
        it 'returns 422 if not a forked project' do
J
jubianchi 已提交
354 355 356
          post api("/projects/#{project.id}/merge_requests", user),
               title: 'Test merge_request',
               target_branch: 'master',
357
               source_branch: 'markdown',
J
jubianchi 已提交
358 359
               author: user,
               target_project_id: fork_project.id
Z
Z.J. van de Weg 已提交
360
          expect(response).to have_http_status(422)
J
jubianchi 已提交
361
        end
I
Izaak Alpert 已提交
362

363
        it 'returns 422 if targeting a different fork' do
J
jubianchi 已提交
364 365 366
          post api("/projects/#{fork_project.id}/merge_requests", user2),
               title: 'Test merge_request',
               target_branch: 'master',
367
               source_branch: 'markdown',
J
jubianchi 已提交
368 369
               author: user2,
               target_project_id: unrelated_project.id
Z
Z.J. van de Weg 已提交
370
          expect(response).to have_http_status(422)
J
jubianchi 已提交
371
        end
I
Izaak Alpert 已提交
372 373
      end

374
      it "returns 201 when target_branch is specified and for the same project" do
H
Hiroyuki Sato 已提交
375
        post api("/projects/#{fork_project.id}/merge_requests", user2),
376
        title: 'Test merge_request', target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: fork_project.id
Z
Z.J. van de Weg 已提交
377
        expect(response).to have_http_status(201)
I
Izaak Alpert 已提交
378
      end
379
    end
V
Valeriy Sizov 已提交
380 381
  end

382 383 384
  describe "DELETE /projects/:id/merge_requests/:merge_request_id" do
    context "when the user is developer" do
      let(:developer) { create(:user) }
Z
Zeger-Jan van de Weg 已提交
385

386 387 388
      before do
        project.team << [developer, :developer]
      end
Z
Zeger-Jan van de Weg 已提交
389

390 391
      it "denies the deletion of the merge request" do
        delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", developer)
Z
Z.J. van de Weg 已提交
392
        expect(response).to have_http_status(403)
393
      end
Z
Zeger-Jan van de Weg 已提交
394
    end
395

396 397 398 399
    context "when the user is project owner" do
      it "destroys the merge request owners can destroy" do
        delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)

Z
Z.J. van de Weg 已提交
400
        expect(response).to have_http_status(200)
401
      end
402
    end
Z
Zeger-Jan van de Weg 已提交
403 404
  end

405
  describe "PUT /projects/:id/merge_requests/:merge_request_id/merge" do
406
    let(:pipeline) { create(:ci_pipeline_without_jobs) }
407

408
    it "returns merge_request in case of success" do
409
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
410

Z
Z.J. van de Weg 已提交
411
      expect(response).to have_http_status(200)
412 413
    end

414
    it "returns 406 if branch can't be merged" do
415 416 417
      allow_any_instance_of(MergeRequest).
        to receive(:can_be_merged?).and_return(false)

418
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
419

Z
Z.J. van de Weg 已提交
420
      expect(response).to have_http_status(406)
421
      expect(json_response['message']).to eq('Branch cannot be merged')
A
Andrew8xx8 已提交
422
    end
D
Dmitriy Zaporozhets 已提交
423

424
    it "returns 405 if merge_request is not open" do
D
Dmitriy Zaporozhets 已提交
425
      merge_request.close
426
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
427
      expect(response).to have_http_status(405)
428
      expect(json_response['message']).to eq('405 Method Not Allowed')
D
Dmitriy Zaporozhets 已提交
429 430
    end

431
    it "returns 405 if merge_request is a work in progress" do
432
      merge_request.update_attribute(:title, "WIP: #{merge_request.title}")
433
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
434
      expect(response).to have_http_status(405)
435 436 437
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

438
    it 'returns 405 if the build failed for a merge request that requires success' do
439
      allow_any_instance_of(MergeRequest).to receive(:mergeable_ci_state?).and_return(false)
440 441

      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
442

Z
Z.J. van de Weg 已提交
443
      expect(response).to have_http_status(405)
444 445 446
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

447
    it "returns 401 if user has no permissions to merge" do
D
Dmitriy Zaporozhets 已提交
448 449
      user2 = create(:user)
      project.team << [user2, :reporter]
450
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user2)
Z
Z.J. van de Weg 已提交
451
      expect(response).to have_http_status(401)
452
      expect(json_response['message']).to eq('401 Unauthorized')
D
Dmitriy Zaporozhets 已提交
453
    end
454

455
    it "returns 409 if the SHA parameter doesn't match" do
456
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), sha: merge_request.diff_head_sha.reverse
457

Z
Z.J. van de Weg 已提交
458
      expect(response).to have_http_status(409)
459 460 461 462
      expect(json_response['message']).to start_with('SHA does not match HEAD of source branch')
    end

    it "succeeds if the SHA parameter matches" do
463
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), sha: merge_request.diff_head_sha
464

Z
Z.J. van de Weg 已提交
465
      expect(response).to have_http_status(200)
466 467
    end

468
    it "enables merge when build succeeds if the ci is active" do
469
      allow_any_instance_of(MergeRequest).to receive(:head_pipeline).and_return(pipeline)
470
      allow(pipeline).to receive(:active?).and_return(true)
471

472
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user), merge_when_build_succeeds: true
473

Z
Z.J. van de Weg 已提交
474
      expect(response).to have_http_status(200)
475 476 477
      expect(json_response['title']).to eq('Test')
      expect(json_response['merge_when_build_succeeds']).to eq(true)
    end
A
Andrew8xx8 已提交
478 479
  end

480
  describe "PUT /projects/:id/merge_requests/:merge_request_id" do
481 482 483 484 485 486 487 488 489
    context "to close a MR" do
      it "returns merge_request" do
        put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: "close"

        expect(response).to have_http_status(200)
        expect(json_response['state']).to eq('closed')
      end
    end

490
    it "updates title and returns merge_request" do
491
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), title: "New title"
Z
Z.J. van de Weg 已提交
492
      expect(response).to have_http_status(200)
493
      expect(json_response['title']).to eq('New title')
V
Valeriy Sizov 已提交
494
    end
495

496
    it "updates description and returns merge_request" do
497
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), description: "New description"
Z
Z.J. van de Weg 已提交
498
      expect(response).to have_http_status(200)
499
      expect(json_response['description']).to eq('New description')
500 501
    end

502 503
    it "updates milestone_id and returns merge_request" do
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), milestone_id: milestone.id
Z
Z.J. van de Weg 已提交
504
      expect(response).to have_http_status(200)
505 506 507
      expect(json_response['milestone']['id']).to eq(milestone.id)
    end

508
    it "returns merge_request with renamed target_branch" do
509
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), target_branch: "wiki"
Z
Z.J. van de Weg 已提交
510
      expect(response).to have_http_status(200)
511
      expect(json_response['target_branch']).to eq('wiki')
512
    end
513

514
    it 'allows special label names' do
515 516 517 518
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user),
        title: 'new issue',
        labels: 'label, label?, label&foo, ?, &'

519 520 521 522 523 524
      expect(response.status).to eq(200)
      expect(json_response['labels']).to include 'label'
      expect(json_response['labels']).to include 'label?'
      expect(json_response['labels']).to include 'label&foo'
      expect(json_response['labels']).to include '?'
      expect(json_response['labels']).to include '&'
525
    end
V
Valeriy Sizov 已提交
526 527
  end

528
  describe "POST /projects/:id/merge_requests/:merge_request_id/comments" do
529
    it "returns comment" do
530 531
      original_count = merge_request.notes.size

532
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment"
Z
Z.J. van de Weg 已提交
533
      expect(response).to have_http_status(201)
534
      expect(json_response['note']).to eq('My comment')
535 536 537
      expect(json_response['author']['name']).to eq(user.name)
      expect(json_response['author']['username']).to eq(user.username)
      expect(merge_request.notes.size).to eq(original_count + 1)
V
Valeriy Sizov 已提交
538
    end
539

540
    it "returns 400 if note is missing" do
541
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
Z
Z.J. van de Weg 已提交
542
      expect(response).to have_http_status(400)
543
    end
544

545
    it "returns 404 if note is attached to non existent merge request" do
546
      post api("/projects/#{project.id}/merge_requests/404/comments", user),
547
        note: 'My comment'
Z
Z.J. van de Weg 已提交
548
      expect(response).to have_http_status(404)
549
    end
V
Valeriy Sizov 已提交
550
  end
551

552
  describe "GET :id/merge_requests/:merge_request_id/comments" do
553
    it "returns merge_request comments ordered by created_at" do
554
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
Z
Z.J. van de Weg 已提交
555
      expect(response).to have_http_status(200)
556
      expect(json_response).to be_an Array
557
      expect(json_response.length).to eq(2)
558 559
      expect(json_response.first['note']).to eq("a comment on a MR")
      expect(json_response.first['author']['id']).to eq(user.id)
560
      expect(json_response.last['note']).to eq("another comment on a MR")
561 562
    end

563
    it "returns a 404 error if merge_request_id not found" do
564
      get api("/projects/#{project.id}/merge_requests/999/comments", user)
Z
Z.J. van de Weg 已提交
565
      expect(response).to have_http_status(404)
566 567
    end
  end
568

569 570 571 572 573 574
  describe 'GET :id/merge_requests/:merge_request_id/closes_issues' do
    it 'returns the issue that will be closed on merge' do
      issue = create(:issue, project: project)
      mr = merge_request.tap do |mr|
        mr.update_attribute(:description, "Closes #{issue.to_reference(mr.project)}")
      end
575

576
      get api("/projects/#{project.id}/merge_requests/#{mr.id}/closes_issues", user)
Z
Z.J. van de Weg 已提交
577
      expect(response).to have_http_status(200)
578 579 580 581 582
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(1)
      expect(json_response.first['id']).to eq(issue.id)
    end

583
    it 'returns an empty array when there are no issues to be closed' do
584
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", user)
Z
Z.J. van de Weg 已提交
585
      expect(response).to have_http_status(200)
586 587 588
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(0)
    end
589 590 591 592 593 594 595 596 597

    it 'handles external issues' do
      jira_project = create(:jira_project, :public, name: 'JIR_EXT1')
      issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
      merge_request = create(:merge_request, :simple, author: user, assignee: user, source_project: jira_project)
      merge_request.update_attribute(:description, "Closes #{issue.to_reference(jira_project)}")

      get api("/projects/#{jira_project.id}/merge_requests/#{merge_request.id}/closes_issues", user)

Z
Z.J. van de Weg 已提交
598
      expect(response).to have_http_status(200)
599 600 601 602 603
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(1)
      expect(json_response.first['title']).to eq(issue.title)
      expect(json_response.first['id']).to eq(issue.id)
    end
604 605
  end

606
  describe 'POST :id/merge_requests/:merge_request_id/subscription' do
607
    it 'subscribes to a merge request' do
608
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
609

Z
Z.J. van de Weg 已提交
610
      expect(response).to have_http_status(201)
611 612 613 614
      expect(json_response['subscribed']).to eq(true)
    end

    it 'returns 304 if already subscribed' do
615
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
616

Z
Z.J. van de Weg 已提交
617
      expect(response).to have_http_status(304)
618
    end
619 620 621 622

    it 'returns 404 if the merge request is not found' do
      post api("/projects/#{project.id}/merge_requests/123/subscription", user)

Z
Z.J. van de Weg 已提交
623
      expect(response).to have_http_status(404)
624
    end
625 626
  end

627
  describe 'DELETE :id/merge_requests/:merge_request_id/subscription' do
628
    it 'unsubscribes from a merge request' do
629
      delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
630

Z
Z.J. van de Weg 已提交
631
      expect(response).to have_http_status(200)
632 633 634 635
      expect(json_response['subscribed']).to eq(false)
    end

    it 'returns 304 if not subscribed' do
636
      delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
637

Z
Z.J. van de Weg 已提交
638
      expect(response).to have_http_status(304)
639
    end
640 641 642 643

    it 'returns 404 if the merge request is not found' do
      post api("/projects/#{project.id}/merge_requests/123/subscription", user)

Z
Z.J. van de Weg 已提交
644
      expect(response).to have_http_status(404)
645
    end
646 647
  end

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
  def mr_with_later_created_and_updated_at_time
    merge_request
    merge_request.created_at += 1.hour
    merge_request.updated_at += 30.minutes
    merge_request.save
    merge_request
  end

  def mr_with_earlier_created_and_updated_at_time
    merge_request_closed
    merge_request_closed.created_at -= 1.hour
    merge_request_closed.updated_at -= 30.minutes
    merge_request_closed.save
    merge_request_closed
  end
V
Valeriy Sizov 已提交
663
end