merge_requests_spec.rb 28.7 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) }
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 to close MR" do
406
    it "returns merge_request" do
407
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: "close"
Z
Z.J. van de Weg 已提交
408
      expect(response).to have_http_status(200)
409
      expect(json_response['state']).to eq('closed')
A
Andrew8xx8 已提交
410 411 412
    end
  end

413
  describe "PUT /projects/:id/merge_requests/:merge_request_id/merge" do
414
    let(:pipeline) { create(:ci_pipeline_without_jobs) }
415

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

Z
Z.J. van de Weg 已提交
419
      expect(response).to have_http_status(200)
420 421
    end

422
    it "returns 406 if branch can't be merged" do
423 424 425
      allow_any_instance_of(MergeRequest).
        to receive(:can_be_merged?).and_return(false)

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

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

432
    it "returns 405 if merge_request is not open" do
D
Dmitriy Zaporozhets 已提交
433
      merge_request.close
434
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
435
      expect(response).to have_http_status(405)
436
      expect(json_response['message']).to eq('405 Method Not Allowed')
D
Dmitriy Zaporozhets 已提交
437 438
    end

439
    it "returns 405 if merge_request is a work in progress" do
440
      merge_request.update_attribute(:title, "WIP: #{merge_request.title}")
441
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
Z
Z.J. van de Weg 已提交
442
      expect(response).to have_http_status(405)
443 444 445
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

446
    it 'returns 405 if the build failed for a merge request that requires success' do
447
      allow_any_instance_of(MergeRequest).to receive(:mergeable_ci_state?).and_return(false)
448 449

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

Z
Z.J. van de Weg 已提交
451
      expect(response).to have_http_status(405)
452 453 454
      expect(json_response['message']).to eq('405 Method Not Allowed')
    end

455
    it "returns 401 if user has no permissions to merge" do
D
Dmitriy Zaporozhets 已提交
456 457
      user2 = create(:user)
      project.team << [user2, :reporter]
458
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user2)
Z
Z.J. van de Weg 已提交
459
      expect(response).to have_http_status(401)
460
      expect(json_response['message']).to eq('401 Unauthorized')
D
Dmitriy Zaporozhets 已提交
461
    end
462

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

Z
Z.J. van de Weg 已提交
466
      expect(response).to have_http_status(409)
467 468 469 470
      expect(json_response['message']).to start_with('SHA does not match HEAD of source branch')
    end

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

Z
Z.J. van de Weg 已提交
473
      expect(response).to have_http_status(200)
474 475
    end

476
    it "enables merge when build succeeds if the ci is active" do
477
      allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline)
478
      allow(pipeline).to receive(:active?).and_return(true)
479

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

Z
Z.J. van de Weg 已提交
482
      expect(response).to have_http_status(200)
483 484 485
      expect(json_response['title']).to eq('Test')
      expect(json_response['merge_when_build_succeeds']).to eq(true)
    end
A
Andrew8xx8 已提交
486 487
  end

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

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

501 502
    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 已提交
503
      expect(response).to have_http_status(200)
504 505 506
      expect(json_response['milestone']['id']).to eq(milestone.id)
    end

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

513
    it 'allows special label names' do
514
      put api("/projects/#{project.id}/merge_requests/#{merge_request.id}",
515 516
              user),
          title: 'new issue',
517 518 519 520 521 522 523
          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 '&'
524
    end
V
Valeriy Sizov 已提交
525 526
  end

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

531
      post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment"
Z
Z.J. van de Weg 已提交
532
      expect(response).to have_http_status(201)
533
      expect(json_response['note']).to eq('My comment')
534 535 536
      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 已提交
537
    end
538

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

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

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

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

568 569 570 571 572 573
  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
574

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

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

    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 已提交
597
      expect(response).to have_http_status(200)
598 599 600 601 602
      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
603 604
  end

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

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

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

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

    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 已提交
622
      expect(response).to have_http_status(404)
623
    end
624 625
  end

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

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

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

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

    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 已提交
643
      expect(response).to have_http_status(404)
644
    end
645 646
  end

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
  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 已提交
662
end