merge_request_spec.rb 21.7 KB
Newer Older
D
Dmitriy Zaporozhets 已提交
1 2
require 'spec_helper'

D
Douwe Maan 已提交
3
describe MergeRequest, models: true do
4 5
  include RepoHelpers

6 7
  subject { create(:merge_request) }

R
Robert Speicher 已提交
8 9 10
  describe 'associations' do
    it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') }
    it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') }
11
    it { is_expected.to belong_to(:merge_user).class_name("User") }
R
Robert Speicher 已提交
12 13 14
    it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
  end

15 16 17 18 19 20 21 22 23 24
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(InternalId) }
    it { is_expected.to include_module(Issuable) }
    it { is_expected.to include_module(Referable) }
    it { is_expected.to include_module(Sortable) }
    it { is_expected.to include_module(Taskable) }
  end

Z
Zeger-Jan van de Weg 已提交
25 26 27 28 29
  describe "act_as_paranoid" do
    it { is_expected.to have_db_column(:deleted_at) }
    it { is_expected.to have_db_index(:deleted_at) }
  end

30
  describe 'validation' do
31 32
    it { is_expected.to validate_presence_of(:target_branch) }
    it { is_expected.to validate_presence_of(:source_branch) }
Z
Zeger-Jan van de Weg 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

    context "Validation of merge user with Merge When Build succeeds" do
      it "allows user to be nil when the feature is disabled" do
        expect(subject).to be_valid
      end

      it "is invalid without merge user" do
        subject.merge_when_build_succeeds = true
        expect(subject).not_to be_valid
      end

      it "is valid with merge user" do
        subject.merge_when_build_succeeds = true
        subject.merge_user = build(:user)

        expect(subject).to be_valid
      end
    end
D
Dmitriy Zaporozhets 已提交
51 52
  end

R
Robert Speicher 已提交
53
  describe 'respond to' do
54 55 56
    it { is_expected.to respond_to(:unchecked?) }
    it { is_expected.to respond_to(:can_be_merged?) }
    it { is_expected.to respond_to(:cannot_be_merged?) }
57 58
    it { is_expected.to respond_to(:merge_params) }
    it { is_expected.to respond_to(:merge_when_build_succeeds) }
59
  end
A
Andrey Kumanyaev 已提交
60

61 62 63 64 65 66
  describe '.in_projects' do
    it 'returns the merge requests for a set of projects' do
      expect(described_class.in_projects(Project.all)).to eq([subject])
    end
  end

67
  describe '#target_branch_sha' do
68
    let(:project) { create(:project) }
69

70
    subject { create(:merge_request, source_project: project, target_project: project) }
71

72
    context 'when the target branch does not exist' do
73 74 75
      before do
        project.repository.raw_repository.delete_branch(subject.target_branch)
      end
76 77

      it 'returns nil' do
78
        expect(subject.target_branch_sha).to be_nil
79 80
      end
    end
81 82 83 84 85 86

    it 'returns memoized value' do
      subject.target_branch_sha = '8ffb3c15a5475e59ae909384297fede4badcb4c7'

      expect(subject.target_branch_sha).to eq '8ffb3c15a5475e59ae909384297fede4badcb4c7'
    end
87 88
  end

89
  describe '#source_branch_sha' do
90 91 92 93 94
    let(:last_branch_commit) { subject.source_project.repository.commit(subject.source_branch) }

    context 'with diffs' do
      subject { create(:merge_request, :with_diffs) }
      it 'returns the sha of the source branch last commit' do
95
        expect(subject.source_branch_sha).to eq(last_branch_commit.sha)
96 97 98
      end
    end

99 100 101
    context 'without diffs' do
      subject { create(:merge_request, :without_diffs) }
      it 'returns the sha of the source branch last commit' do
102
        expect(subject.source_branch_sha).to eq(last_branch_commit.sha)
103 104 105
      end
    end

106 107 108
    context 'when the merge request is being created' do
      subject { build(:merge_request, source_branch: nil, compare_commits: []) }
      it 'returns nil' do
109
        expect(subject.source_branch_sha).to be_nil
110 111
      end
    end
112 113 114 115 116 117

    it 'returns memoized value' do
      subject.source_branch_sha = '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b'

      expect(subject.source_branch_sha).to eq '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b'
    end
118 119
  end

120 121 122 123 124 125 126 127 128
  describe '#to_reference' do
    it 'returns a String reference to the object' do
      expect(subject.to_reference).to eq "!#{subject.iid}"
    end

    it 'supports a cross-project reference' do
      cross = double('project')
      expect(subject.to_reference(cross)).to eq "#{subject.source_project.to_reference}!#{subject.iid}"
    end
129
  end
130

S
Sean McGivern 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
  describe '#diffs' do
    let(:merge_request) { build(:merge_request) }
    let(:options) { { paths: ['a/b', 'b/a', 'c/*'] } }

    context 'when there are MR diffs' do
      it 'delegates to the MR diffs' do
        merge_request.merge_request_diff = MergeRequestDiff.new

        expect(merge_request.merge_request_diff).to receive(:diffs).with(options)

        merge_request.diffs(options)
      end
    end

    context 'when there are no MR diffs' do
      it 'delegates to the compare object' do
        merge_request.compare = double(:compare)

        expect(merge_request.compare).to receive(:diffs).with(options)

        merge_request.diffs(options)
      end
    end
  end

156
  describe "#mr_and_commit_notes" do
157
    let!(:merge_request) { create(:merge_request) }
158 159

    before do
160
      allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
161 162
      create(:note_on_commit, commit_id: merge_request.commits.first.id,
                              project: merge_request.project)
D
Dmitriy Zaporozhets 已提交
163
      create(:note, noteable: merge_request, project: merge_request.project)
164 165 166
    end

    it "should include notes for commits" do
167 168
      expect(merge_request.commits).not_to be_empty
      expect(merge_request.mr_and_commit_notes.count).to eq(2)
169
    end
170 171

    it "should include notes for commits from target project as well" do
172 173 174
      create(:note_on_commit, commit_id: merge_request.commits.first.id,
                              project: merge_request.target_project)

175 176 177
      expect(merge_request.commits).not_to be_empty
      expect(merge_request.mr_and_commit_notes.count).to eq(3)
    end
178
  end
179 180 181

  describe '#is_being_reassigned?' do
    it 'returns true if the merge_request assignee has changed' do
182
      subject.assignee = create(:user)
183
      expect(subject.is_being_reassigned?).to be_truthy
184 185
    end
    it 'returns false if the merge request assignee has not changed' do
186
      expect(subject.is_being_reassigned?).to be_falsey
187 188
    end
  end
I
Izaak Alpert 已提交
189 190 191

  describe '#for_fork?' do
    it 'returns true if the merge request is for a fork' do
D
Dmitriy Zaporozhets 已提交
192 193
      subject.source_project = create(:project, namespace: create(:group))
      subject.target_project = create(:project, namespace: create(:group))
I
Izaak Alpert 已提交
194

195
      expect(subject.for_fork?).to be_truthy
I
Izaak Alpert 已提交
196
    end
D
Dmitriy Zaporozhets 已提交
197

I
Izaak Alpert 已提交
198
    it 'returns false if is not for a fork' do
199
      expect(subject.for_fork?).to be_falsey
I
Izaak Alpert 已提交
200 201 202
    end
  end

203 204 205
  describe 'detection of issues to be closed' do
    let(:issue0) { create :issue, project: subject.project }
    let(:issue1) { create :issue, project: subject.project }
206 207 208 209

    let(:commit0) { double('commit0', safe_message: "Fixes #{issue0.to_reference}") }
    let(:commit1) { double('commit1', safe_message: "Fixes #{issue0.to_reference}") }
    let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") }
210 211

    before do
212
      subject.project.team << [subject.author, :developer]
213
      allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
214 215 216
    end

    it 'accesses the set of issues that will be closed on acceptance' do
217 218
      allow(subject.project).to receive(:default_branch).
        and_return(subject.target_branch)
219

220 221 222
      closed = subject.closes_issues

      expect(closed).to include(issue0, issue1)
223 224 225
    end

    it 'only lists issues as to be closed if it targets the default branch' do
226
      allow(subject.project).to receive(:default_branch).and_return('master')
227 228
      subject.target_branch = 'something-else'

229
      expect(subject.closes_issues).to be_empty
230
    end
231 232 233

    it 'detects issues mentioned in the description' do
      issue2 = create(:issue, project: subject.project)
234
      subject.description = "Closes #{issue2.to_reference}"
235 236
      allow(subject.project).to receive(:default_branch).
        and_return(subject.target_branch)
237

238
      expect(subject.closes_issues).to include(issue2)
239
    end
240 241
  end

242
  describe "#work_in_progress?" do
243 244 245
    ['WIP ', 'WIP:', 'WIP: ', '[WIP]', '[WIP] ', ' [WIP] WIP [WIP] WIP: WIP '].each do |wip_prefix|
      it "detects the '#{wip_prefix}' prefix" do
        subject.title = "#{wip_prefix}#{subject.title}"
246
        expect(subject.work_in_progress?).to eq true
247
      end
T
Ted Hogan 已提交
248 249
    end

250 251
    it "doesn't detect WIP for words starting with WIP" do
      subject.title = "Wipwap #{subject.title}"
252
      expect(subject.work_in_progress?).to eq false
253 254
    end

255 256
    it "doesn't detect WIP for words containing with WIP" do
      subject.title = "WupWipwap #{subject.title}"
257
      expect(subject.work_in_progress?).to eq false
258 259
    end

260
    it "doesn't detect WIP by default" do
261
      expect(subject.work_in_progress?).to eq false
262 263 264
    end
  end

Z
Zeger-Jan van de Weg 已提交
265
  describe '#can_remove_source_branch?' do
Z
Zeger-Jan van de Weg 已提交
266 267
    let(:user) { create(:user) }
    let(:user2) { create(:user) }
268 269 270 271

    before do
      subject.source_project.team << [user, :master]

Z
Zeger-Jan van de Weg 已提交
272 273 274 275
      subject.source_branch = "feature"
      subject.target_branch = "master"
      subject.save!
    end
276

Z
Zeger-Jan van de Weg 已提交
277 278
    it "can't be removed when its a protected branch" do
      allow(subject.source_project).to receive(:protected_branch?).and_return(true)
279 280 281 282
      expect(subject.can_remove_source_branch?(user)).to be_falsey
    end

    it "cant remove a root ref" do
Z
Zeger-Jan van de Weg 已提交
283 284
      subject.source_branch = "master"
      subject.target_branch = "feature"
285 286 287 288

      expect(subject.can_remove_source_branch?(user)).to be_falsey
    end

Z
Zeger-Jan van de Weg 已提交
289 290 291 292
    it "is unable to remove the source branch for a project the user cannot push to" do
      expect(subject.can_remove_source_branch?(user2)).to be_falsey
    end

293
    it "can be removed if the last commit is the head of the source branch" do
294
      allow(subject.source_project).to receive(:commit).and_return(subject.diff_head_commit)
295

Z
Zeger-Jan van de Weg 已提交
296
      expect(subject.can_remove_source_branch?(user)).to be_truthy
297
    end
298 299

    it "cannot be removed if the last commit is not also the head of the source branch" do
300 301
      subject.source_branch = "lfs"

302 303
      expect(subject.can_remove_source_branch?(user)).to be_falsey
    end
304 305
  end

306
  describe "#reset_merge_when_build_succeeds" do
307 308 309 310
    let(:merge_if_green) do
      create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user),
                             merge_params: { "should_remove_source_branch" => "1", "commit_message" => "msg" }
    end
Z
Zeger-Jan van de Weg 已提交
311

312 313 314 315 316
    it "sets the item to false" do
      merge_if_green.reset_merge_when_build_succeeds
      merge_if_green.reload

      expect(merge_if_green.merge_when_build_succeeds).to be_falsey
317 318
      expect(merge_if_green.merge_params["should_remove_source_branch"]).to be_nil
      expect(merge_if_green.merge_params["commit_message"]).to be_nil
319 320 321
    end
  end

322
  describe "#hook_attrs" do
323 324 325 326 327 328 329 330 331 332 333
    let(:attrs_hash) { subject.hook_attrs.to_h }

    [:source, :target].each do |key|
      describe "#{key} key" do
        include_examples 'project hook data', project_key: key do
          let(:data)    { attrs_hash }
          let(:project) { subject.send("#{key}_project") }
        end
      end
    end

334
    it "has all the required keys" do
335 336 337 338
      expect(attrs_hash).to include(:source)
      expect(attrs_hash).to include(:target)
      expect(attrs_hash).to include(:last_commit)
      expect(attrs_hash).to include(:work_in_progress)
339
    end
340 341 342 343 344 345
  end

  describe '#diverged_commits_count' do
    let(:project)      { create(:project) }
    let(:fork_project) { create(:project, forked_from_project: project) }

346
    context 'when the target branch does not exist anymore' do
347 348 349 350 351 352
      subject { create(:merge_request, source_project: project, target_project: project) }

      before do
        project.repository.raw_repository.delete_branch(subject.target_branch)
        subject.reload
      end
353 354 355 356 357 358 359 360 361 362

      it 'does not crash' do
        expect{ subject.diverged_commits_count }.not_to raise_error
      end

      it 'returns 0' do
        expect(subject.diverged_commits_count).to eq(0)
      end
    end

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    context 'diverged on same repository' do
      subject(:merge_request_with_divergence) { create(:merge_request, :diverged, source_project: project, target_project: project) }

      it 'counts commits that are on target branch but not on source branch' do
        expect(subject.diverged_commits_count).to eq(5)
      end
    end

    context 'diverged on fork' do
      subject(:merge_request_fork_with_divergence) { create(:merge_request, :diverged, source_project: fork_project, target_project: project) }

      it 'counts commits that are on target branch but not on source branch' do
        expect(subject.diverged_commits_count).to eq(5)
      end
    end

    context 'rebased on fork' do
      subject(:merge_request_rebased) { create(:merge_request, :rebased, source_project: fork_project, target_project: project) }

      it 'counts commits that are on target branch but not on source branch' do
        expect(subject.diverged_commits_count).to eq(0)
      end
    end

    describe 'caching' do
      before(:example) do
        allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new)
      end

      it 'caches the output' do
        expect(subject).to receive(:compute_diverged_commits_count).
          once.
          and_return(2)

        subject.diverged_commits_count
        subject.diverged_commits_count
      end

      it 'invalidates the cache when the source sha changes' do
        expect(subject).to receive(:compute_diverged_commits_count).
          twice.
          and_return(2)

        subject.diverged_commits_count
407
        allow(subject).to receive(:source_branch_sha).and_return('123abc')
408 409 410 411 412 413 414 415 416
        subject.diverged_commits_count
      end

      it 'invalidates the cache when the target sha changes' do
        expect(subject).to receive(:compute_diverged_commits_count).
          twice.
          and_return(2)

        subject.diverged_commits_count
417
        allow(subject).to receive(:target_branch_sha).and_return('123abc')
418 419 420
        subject.diverged_commits_count
      end
    end
421 422
  end

423
  it_behaves_like 'an editable mentionable' do
424
    subject { create(:merge_request) }
425

426 427
    let(:backref_text) { "merge request #{subject.to_reference}" }
    let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
428
  end
V
Vinnie Okada 已提交
429 430

  it_behaves_like 'a Taskable' do
431
    subject { create :merge_request, :simple }
V
Vinnie Okada 已提交
432
  end
433

434
  describe '#pipeline' do
435
    describe 'when the source project exists' do
436
      it 'returns the latest pipeline' do
437
        pipeline = double(:ci_pipeline, ref: 'master')
438

439
        allow(subject).to receive(:diff_head_sha).and_return('123abc')
440

441
        expect(subject.source_project).to receive(:pipeline).
K
Kamil Trzcinski 已提交
442
          with('123abc', 'master').
443
          and_return(pipeline)
444

445
        expect(subject.pipeline).to eq(pipeline)
446 447 448 449 450 451 452
      end
    end

    describe 'when the source project does not exist' do
      it 'returns nil' do
        allow(subject).to receive(:source_project).and_return(nil)

453
        expect(subject.pipeline).to be_nil
454 455 456
      end
    end
  end
Y
Yorick Peterse 已提交
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

  describe '#participants' do
    let(:project) { create(:project, :public) }

    let(:mr) do
      create(:merge_request, source_project: project, target_project: project)
    end

    let!(:note1) do
      create(:note_on_merge_request, noteable: mr, project: project, note: 'a')
    end

    let!(:note2) do
      create(:note_on_merge_request, noteable: mr, project: project, note: 'b')
    end

    it 'includes the merge request author' do
      expect(mr.participants).to include(mr.author)
    end

    it 'includes the authors of the notes' do
      expect(mr.participants).to include(note1.author, note2.author)
    end
  end
J
Josh Frye 已提交
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497

  describe 'cached counts' do
    it 'updates when assignees change' do
      user1 = create(:user)
      user2 = create(:user)
      mr = create(:merge_request, assignee: user1)

      expect(user1.assigned_open_merge_request_count).to eq(1)
      expect(user2.assigned_open_merge_request_count).to eq(0)

      mr.assignee = user2
      mr.save

      expect(user1.assigned_open_merge_request_count).to eq(0)
      expect(user2.assigned_open_merge_request_count).to eq(1)
    end
  end
498 499 500 501 502 503 504 505 506

  describe '#check_if_can_be_merged' do
    let(:project) { create(:project, only_allow_merge_if_build_succeeds: true) }

    subject { create(:merge_request, source_project: project, merge_status: :unchecked) }

    context 'when it is not broken and has no conflicts' do
      it 'is marked as mergeable' do
        allow(subject).to receive(:broken?) { false }
507
        allow(project.repository).to receive(:can_be_merged?).and_return(true)
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523

        expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged')
      end
    end

    context 'when broken' do
      before { allow(subject).to receive(:broken?) { true } }

      it 'becomes unmergeable' do
        expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
      end
    end

    context 'when it has conflicts' do
      before do
        allow(subject).to receive(:broken?) { false }
524
        allow(project.repository).to receive(:can_be_merged?).and_return(false)
525 526 527 528 529 530 531 532 533
      end

      it 'becomes unmergeable' do
        expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
      end
    end
  end

  describe '#mergeable?' do
534 535 536 537
    let(:project) { create(:project) }

    subject { create(:merge_request, source_project: project) }

538 539
    it 'returns false if #mergeable_state? is false' do
      expect(subject).to receive(:mergeable_state?) { false }
540

541
      expect(subject.mergeable?).to be_falsey
542 543
    end

544
    it 'return true if #mergeable_state? is true and the MR #can_be_merged? is true' do
545 546
      allow(subject).to receive(:mergeable_state?) { true }
      expect(subject).to receive(:check_if_can_be_merged)
547
      expect(subject).to receive(:can_be_merged?) { true }
548 549 550 551 552 553 554

      expect(subject.mergeable?).to be_truthy
    end
  end

  describe '#mergeable_state?' do
    let(:project) { create(:project) }
555 556 557

    subject { create(:merge_request, source_project: project) }

558
    it 'checks if merge request can be merged' do
559
      allow(subject).to receive(:mergeable_ci_state?) { true }
560 561 562 563 564 565 566 567 568
      expect(subject).to receive(:check_if_can_be_merged)

      subject.mergeable?
    end

    context 'when not open' do
      before { subject.close }

      it 'returns false' do
569
        expect(subject.mergeable_state?).to be_falsey
570 571 572 573 574 575 576
      end
    end

    context 'when working in progress' do
      before { subject.title = 'WIP MR' }

      it 'returns false' do
577
        expect(subject.mergeable_state?).to be_falsey
578 579 580 581 582 583 584
      end
    end

    context 'when broken' do
      before { allow(subject).to receive(:broken?) { true } }

      it 'returns false' do
585
        expect(subject.mergeable_state?).to be_falsey
586 587 588 589 590 591
      end
    end

    context 'when failed' do
      before { allow(subject).to receive(:broken?) { false } }

592 593 594
      context 'when project settings restrict to merge only if build succeeds and build failed' do
        before do
          project.only_allow_merge_if_build_succeeds = true
595
          allow(subject).to receive(:mergeable_ci_state?) { false }
596 597 598 599
        end

        it 'returns false' do
          expect(subject.mergeable_state?).to be_falsey
600 601 602 603 604
        end
      end
    end
  end

605
  describe '#mergeable_ci_state?' do
606
    let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) }
R
Rémy Coutable 已提交
607
    let(:pipeline) { create(:ci_empty_pipeline) }
608 609 610

    subject { build(:merge_request, target_project: project) }

611
    context 'when it is only allowed to merge when build is green' do
R
Rémy Coutable 已提交
612
      context 'and a failed pipeline is associated' do
613
        before do
R
Rémy Coutable 已提交
614 615
          pipeline.statuses << create(:commit_status, status: 'failed', project: project)
          allow(subject).to receive(:pipeline) { pipeline }
616
        end
617

618
        it { expect(subject.mergeable_ci_state?).to be_falsey }
619 620
      end

R
Rémy Coutable 已提交
621
      context 'when no pipeline is associated' do
622
        before do
R
Rémy Coutable 已提交
623
          allow(subject).to receive(:pipeline) { nil }
624 625 626
        end

        it { expect(subject.mergeable_ci_state?).to be_truthy }
627 628 629
      end
    end

630
    context 'when merges are not restricted to green builds' do
631 632
      subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_build_succeeds: false)) }

R
Rémy Coutable 已提交
633
      context 'and a failed pipeline is associated' do
634
        before do
R
Rémy Coutable 已提交
635 636
          pipeline.statuses << create(:commit_status, status: 'failed', project: project)
          allow(subject).to receive(:pipeline) { pipeline }
637 638 639 640 641
        end

        it { expect(subject.mergeable_ci_state?).to be_truthy }
      end

R
Rémy Coutable 已提交
642
      context 'when no pipeline is associated' do
643
        before do
R
Rémy Coutable 已提交
644
          allow(subject).to receive(:pipeline) { nil }
645 646 647
        end

        it { expect(subject.mergeable_ci_state?).to be_truthy }
648 649 650
      end
    end
  end
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688

  describe "#reload_diff" do
    let(:note) { create(:diff_note_on_merge_request, project: subject.project, noteable: subject) }

    let(:commit) { subject.project.commit(sample_commit.id) }

    it "reloads the diff content" do
      expect(subject.merge_request_diff).to receive(:reload_content)

      subject.reload_diff
    end

    it "updates diff note positions" do
      old_diff_refs = subject.diff_refs

      merge_request_diff = subject.merge_request_diff

      # Update merge_request_diff so that #diff_refs will return commit.diff_refs
      allow(merge_request_diff).to receive(:reload_content) do
        merge_request_diff.base_commit_sha = commit.parent_id
        merge_request_diff.start_commit_sha = commit.parent_id
        merge_request_diff.head_commit_sha = commit.sha
      end

      expect(Notes::DiffPositionUpdateService).to receive(:new).with(
        subject.project,
        nil,
        old_diff_refs: old_diff_refs,
        new_diff_refs: commit.diff_refs,
        paths: note.position.paths
      ).and_call_original
      expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note)

      expect_any_instance_of(DiffNote).to receive(:save).once

      subject.reload_diff
    end
  end
D
Dmitriy Zaporozhets 已提交
689
end