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

J
Jeroen van Baarsen 已提交
3
describe API::API, 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) }
S
Stan Hu 已提交
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) }
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
I
Izaak Alpert 已提交
18
    project.team << [user, :reporters]
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)
V
Valeriy Sizov 已提交
36
      end
37

38
      it "returns an array of all merge_requests" do
39
        get api("/projects/#{project.id}/merge_requests?state", user)
Z
Z.J. van de Weg 已提交
40
        expect(response).to have_http_status(200)
41 42 43
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(3)
        expect(json_response.last['title']).to eq(merge_request.title)
44
      end
45

46
      it "returns an array of open merge_requests" do
47
        get api("/projects/#{project.id}/merge_requests?state=opened", 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(1)
        expect(json_response.last['title']).to eq(merge_request.title)
52
      end
53

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

62
      it "returns an array of merged merge_requests" do
63
        get api("/projects/#{project.id}/merge_requests?state=merged", user)
Z
Z.J. van de Weg 已提交
64
        expect(response).to have_http_status(200)
65 66 67
        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)
68
      end
69 70 71 72 73 74 75

      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

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

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

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

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

115
  describe "GET /projects/:id/merge_requests/:merge_request_id" do
116 117 118
    it 'exposes known attributes' do
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)

Z
Z.J. van de Weg 已提交
119
      expect(response).to have_http_status(200)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
      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')
141 142
      expect(json_response['should_close_merge_request']).to be_falsy
      expect(json_response['force_close_merge_request']).to be_falsy
143 144
    end

145
    it "returns merge_request" do
146
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user)
Z
Z.J. van de Weg 已提交
147
      expect(response).to have_http_status(200)
148 149
      expect(json_response['title']).to eq(merge_request.title)
      expect(json_response['iid']).to eq(merge_request.iid)
150
      expect(json_response['work_in_progress']).to eq(false)
151
      expect(json_response['merge_status']).to eq('can_be_merged')
152 153
      expect(json_response['should_close_merge_request']).to be_falsy
      expect(json_response['force_close_merge_request']).to be_falsy
V
Valeriy Sizov 已提交
154
    end
155

156
    it 'returns merge_request by iid' do
157 158
      url = "/projects/#{project.id}/merge_requests?iid=#{merge_request.iid}"
      get api(url, user)
159 160 161
      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
162 163
    end

164
    it "returns a 404 error if merge_request_id not found" do
165
      get api("/projects/#{project.id}/merge_requests/999", user)
Z
Z.J. van de Weg 已提交
166
      expect(response).to have_http_status(404)
167
    end
168 169 170 171

    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) }

172
      it "returns merge_request" do
173
        get api("/projects/#{project.id}/merge_requests/#{merge_request_wip.id}", user)
Z
Z.J. van de Weg 已提交
174
        expect(response).to have_http_status(200)
175 176 177
        expect(json_response['work_in_progress']).to eq(true)
      end
    end
V
Valeriy Sizov 已提交
178 179
  end

180
  describe 'GET /projects/:id/merge_requests/:merge_request_id/commits' do
181
    context 'valid merge request' do
182
      before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user) }
183 184 185 186 187 188 189 190 191
      let(:commit) { merge_request.commits.first }

      it { expect(response.status).to eq 200 }
      it { expect(json_response.size).to eq(merge_request.commits.size) }
      it { expect(json_response.first['id']).to eq(commit.id) }
      it { expect(json_response.first['title']).to eq(commit.title) }
    end

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

197
  describe 'GET /projects/:id/merge_requests/:merge_request_id/changes' do
198
    it 'returns the change information of the merge_request' do
199
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/changes", user)
200 201 202 203 204
      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
205
      get api("/projects/#{project.id}/merge_requests/999/changes", user)
Z
Z.J. van de Weg 已提交
206
      expect(response).to have_http_status(404)
207 208 209
    end
  end

V
Valeriy Sizov 已提交
210
  describe "POST /projects/:id/merge_requests" do
I
Izaak Alpert 已提交
211
    context 'between branches projects' do
212
      it "returns merge_request" do
H
Hiroyuki Sato 已提交
213
        post api("/projects/#{project.id}/merge_requests", user),
214
             title: 'Test merge_request',
215
             source_branch: 'feature_conflict',
216 217
             target_branch: 'master',
             author: user,
218 219
             labels: 'label, label2',
             milestone_id: milestone.id
Z
Z.J. van de Weg 已提交
220
        expect(response).to have_http_status(201)
221 222
        expect(json_response['title']).to eq('Test merge_request')
        expect(json_response['labels']).to eq(['label', 'label2'])
223
        expect(json_response['milestone']['id']).to eq(milestone.id)
I
Izaak Alpert 已提交
224
      end
225

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

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

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

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

250
      it 'allows special label names' do
251 252
        post api("/projects/#{project.id}/merge_requests", user),
             title: 'Test merge_request',
253
             source_branch: 'markdown',
254 255
             target_branch: 'master',
             author: user,
256 257 258 259 260 261 262
             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 '&'
263
      end
J
jubianchi 已提交
264 265 266 267 268

      context 'with existing MR' do
        before do
          post api("/projects/#{project.id}/merge_requests", user),
               title: 'Test merge_request',
269
               source_branch: 'feature_conflict',
J
jubianchi 已提交
270 271 272 273 274
               target_branch: 'master',
               author: user
          @mr = MergeRequest.all.last
        end

275
        it 'returns 409 when MR already exists for source/target' do
J
jubianchi 已提交
276 277 278
          expect do
            post api("/projects/#{project.id}/merge_requests", user),
                 title: 'New test merge_request',
279
                 source_branch: 'feature_conflict',
J
jubianchi 已提交
280 281 282
                 target_branch: 'master',
                 author: user
          end.to change { MergeRequest.count }.by(0)
Z
Z.J. van de Weg 已提交
283
          expect(response).to have_http_status(409)
J
jubianchi 已提交
284 285
        end
      end
286
    end
287

I
Izaak Alpert 已提交
288
    context 'forked projects' do
D
Dmitriy Zaporozhets 已提交
289 290 291
      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 已提交
292 293 294 295 296

      before :each do |each|
        fork_project.team << [user2, :reporters]
      end

297
      it "returns merge_request" do
H
Hiroyuki Sato 已提交
298
        post api("/projects/#{fork_project.id}/merge_requests", user2),
299 300
          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 已提交
301
        expect(response).to have_http_status(201)
302 303
        expect(json_response['title']).to eq('Test merge_request')
        expect(json_response['description']).to eq('Test description for Test merge_request')
I
Izaak Alpert 已提交
304 305
      end

306
      it "does not return 422 when source_branch equals target_branch" do
307 308 309
        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 已提交
310
        post api("/projects/#{fork_project.id}/merge_requests", user2),
311
        title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id
Z
Z.J. van de Weg 已提交
312
        expect(response).to have_http_status(201)
313
        expect(json_response['title']).to eq('Test merge_request')
I
Izaak Alpert 已提交
314 315
      end

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

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

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

J
jubianchi 已提交
334
      context 'when target_branch is specified' do
335
        it 'returns 422 if not a forked project' do
J
jubianchi 已提交
336 337 338
          post api("/projects/#{project.id}/merge_requests", user),
               title: 'Test merge_request',
               target_branch: 'master',
339
               source_branch: 'markdown',
J
jubianchi 已提交
340 341
               author: user,
               target_project_id: fork_project.id
Z
Z.J. van de Weg 已提交
342
          expect(response).to have_http_status(422)
J
jubianchi 已提交
343
        end
I
Izaak Alpert 已提交
344

345
        it 'returns 422 if targeting a different fork' do
J
jubianchi 已提交
346 347 348
          post api("/projects/#{fork_project.id}/merge_requests", user2),
               title: 'Test merge_request',
               target_branch: 'master',
349
               source_branch: 'markdown',
J
jubianchi 已提交
350 351
               author: user2,
               target_project_id: unrelated_project.id
Z
Z.J. van de Weg 已提交
352
          expect(response).to have_http_status(422)
J
jubianchi 已提交
353
        end
I
Izaak Alpert 已提交
354 355
      end

356
      it "returns 201 when target_branch is specified and for the same project" do
H
Hiroyuki Sato 已提交
357
        post api("/projects/#{fork_project.id}/merge_requests", user2),
358
        title: 'Test merge_request', target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: fork_project.id
Z
Z.J. van de Weg 已提交
359
        expect(response).to have_http_status(201)
I
Izaak Alpert 已提交
360
      end
361
    end
V
Valeriy Sizov 已提交
362 363
  end

364 365 366
  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 已提交
367

368 369 370
      before do
        project.team << [developer, :developer]
      end
Z
Zeger-Jan van de Weg 已提交
371

372 373
      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 已提交
374
        expect(response).to have_http_status(403)
375
      end
Z
Zeger-Jan van de Weg 已提交
376
    end
377

378 379 380 381
    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 已提交
382
        expect(response).to have_http_status(200)
383
      end
384
    end
Z
Zeger-Jan van de Weg 已提交
385 386
  end

387
  describe "PUT /projects/:id/merge_requests/:merge_request_id to close MR" do
388
    it "returns merge_request" do
389
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: "close"
Z
Z.J. van de Weg 已提交
390
      expect(response).to have_http_status(200)
391
      expect(json_response['state']).to eq('closed')
A
Andrew8xx8 已提交
392 393 394
    end
  end

395
  describe "PUT /projects/:id/merge_requests/:merge_request_id/merge" do
396
    let(:pipeline) { create(:ci_pipeline_without_jobs) }
397

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

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

404
    it "returns 406 if branch can't be merged" do
405 406 407
      allow_any_instance_of(MergeRequest).
        to receive(:can_be_merged?).and_return(false)

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

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

414
    it "returns 405 if merge_request is not open" do
D
Dmitriy Zaporozhets 已提交
415
      merge_request.close
416
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
417
      expect(response).to have_http_status(405)
418
      expect(json_response['message']).to eq('405 Method Not Allowed')
D
Dmitriy Zaporozhets 已提交
419 420
    end

421
    it "returns 405 if merge_request is a work in progress" do
422
      merge_request.update_attribute(:title, "WIP: #{merge_request.title}")
423
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
424
      expect(response).to have_http_status(405)
425 426 427
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

428
    it 'returns 405 if the build failed for a merge request that requires success' do
429
      allow_any_instance_of(MergeRequest).to receive(:mergeable_ci_state?).and_return(false)
430 431

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

Z
Z.J. van de Weg 已提交
433
      expect(response).to have_http_status(405)
434 435 436
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

437
    it "returns 401 if user has no permissions to merge" do
D
Dmitriy Zaporozhets 已提交
438 439
      user2 = create(:user)
      project.team << [user2, :reporter]
440
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user2)
Z
Z.J. van de Weg 已提交
441
      expect(response).to have_http_status(401)
442
      expect(json_response['message']).to eq('401 Unauthorized')
D
Dmitriy Zaporozhets 已提交
443
    end
444

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

Z
Z.J. van de Weg 已提交
448
      expect(response).to have_http_status(409)
449 450 451 452
      expect(json_response['message']).to start_with('SHA does not match HEAD of source branch')
    end

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

Z
Z.J. van de Weg 已提交
455
      expect(response).to have_http_status(200)
456 457
    end

458
    it "enables merge when build succeeds if the ci is active" do
459
      allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline)
460
      allow(pipeline).to receive(:active?).and_return(true)
461

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

Z
Z.J. van de Weg 已提交
464
      expect(response).to have_http_status(200)
465 466 467
      expect(json_response['title']).to eq('Test')
      expect(json_response['merge_when_build_succeeds']).to eq(true)
    end
A
Andrew8xx8 已提交
468 469
  end

470
  describe "PUT /projects/:id/merge_requests/:merge_request_id" do
471
    it "updates title and returns merge_request" do
472
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), title: "New title"
Z
Z.J. van de Weg 已提交
473
      expect(response).to have_http_status(200)
474
      expect(json_response['title']).to eq('New title')
V
Valeriy Sizov 已提交
475
    end
476

477
    it "updates description and returns merge_request" do
478
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), description: "New description"
Z
Z.J. van de Weg 已提交
479
      expect(response).to have_http_status(200)
480
      expect(json_response['description']).to eq('New description')
481 482
    end

483 484
    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 已提交
485
      expect(response).to have_http_status(200)
486 487 488
      expect(json_response['milestone']['id']).to eq(milestone.id)
    end

489
    it "returns 400 when source_branch is specified" do
490
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user),
491
      source_branch: "master", target_branch: "master"
Z
Z.J. van de Weg 已提交
492
      expect(response).to have_http_status(400)
493 494
    end

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

501
    it 'allows special label names' do
502
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}",
503 504
              user),
          title: 'new issue',
505 506 507 508 509 510 511
          labels: 'label, label?, label&foo, ?, &'
      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 '&'
512
    end
V
Valeriy Sizov 已提交
513 514
  end

515
  describe "POST /projects/:id/merge_requests/:merge_request_id/comments" do
516
    it "returns comment" do
517 518
      original_count = merge_request.notes.size

519
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment"
Z
Z.J. van de Weg 已提交
520
      expect(response).to have_http_status(201)
521
      expect(json_response['note']).to eq('My comment')
522 523 524
      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 已提交
525
    end
526

527
    it "returns 400 if note is missing" do
528
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
Z
Z.J. van de Weg 已提交
529
      expect(response).to have_http_status(400)
530
    end
531

532
    it "returns 404 if note is attached to non existent merge request" do
533
      post api("/projects/#{project.id}/merge_requests/404/comments", user),
J
jubianchi 已提交
534
           note: 'My comment'
Z
Z.J. van de Weg 已提交
535
      expect(response).to have_http_status(404)
536
    end
V
Valeriy Sizov 已提交
537
  end
538

539
  describe "GET :id/merge_requests/:merge_request_id/comments" do
540
    it "returns merge_request comments ordered by created_at" do
541
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user)
Z
Z.J. van de Weg 已提交
542
      expect(response).to have_http_status(200)
543
      expect(json_response).to be_an Array
544
      expect(json_response.length).to eq(2)
545 546
      expect(json_response.first['note']).to eq("a comment on a MR")
      expect(json_response.first['author']['id']).to eq(user.id)
547
      expect(json_response.last['note']).to eq("another comment on a MR")
548 549
    end

550
    it "returns a 404 error if merge_request_id not found" do
551
      get api("/projects/#{project.id}/merge_requests/999/comments", user)
Z
Z.J. van de Weg 已提交
552
      expect(response).to have_http_status(404)
553 554
    end
  end
555

556 557 558 559 560 561
  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
562

563
      get api("/projects/#{project.id}/merge_requests/#{mr.id}/closes_issues", user)
Z
Z.J. van de Weg 已提交
564
      expect(response).to have_http_status(200)
565 566 567 568 569
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(1)
      expect(json_response.first['id']).to eq(issue.id)
    end

570
    it 'returns an empty array when there are no issues to be closed' do
571
      get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", user)
Z
Z.J. van de Weg 已提交
572
      expect(response).to have_http_status(200)
573 574 575
      expect(json_response).to be_an Array
      expect(json_response.length).to eq(0)
    end
576 577 578 579 580 581 582 583 584

    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 已提交
585
      expect(response).to have_http_status(200)
586 587 588 589 590
      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
591 592
  end

593
  describe 'POST :id/merge_requests/:merge_request_id/subscription' do
594
    it 'subscribes to a merge request' do
595
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
596

Z
Z.J. van de Weg 已提交
597
      expect(response).to have_http_status(201)
598 599 600 601
      expect(json_response['subscribed']).to eq(true)
    end

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

Z
Z.J. van de Weg 已提交
604
      expect(response).to have_http_status(304)
605
    end
606 607 608 609

    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 已提交
610
      expect(response).to have_http_status(404)
611
    end
612 613
  end

614
  describe 'DELETE :id/merge_requests/:merge_request_id/subscription' do
615
    it 'unsubscribes from a merge request' do
616
      delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
617

Z
Z.J. van de Weg 已提交
618
      expect(response).to have_http_status(200)
619 620 621 622
      expect(json_response['subscribed']).to eq(false)
    end

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

Z
Z.J. van de Weg 已提交
625
      expect(response).to have_http_status(304)
626
    end
627 628 629 630

    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 已提交
631
      expect(response).to have_http_status(404)
632
    end
633 634
  end

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
  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 已提交
650
end