merge_request_spec.rb 7.09 KB
Newer Older
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
1 2 3 4
# == Schema Information
#
# Table name: merge_requests
#
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
5 6 7 8 9 10 11
#  id                :integer          not null, primary key
#  target_branch     :string(255)      not null
#  source_branch     :string(255)      not null
#  source_project_id :integer          not null
#  author_id         :integer
#  assignee_id       :integer
#  title             :string(255)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
12 13
#  created_at        :datetime
#  updated_at        :datetime
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
14 15 16 17 18
#  milestone_id      :integer
#  state             :string(255)
#  merge_status      :string(255)
#  target_project_id :integer          not null
#  iid               :integer
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
19
#  description       :text
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
20
#  position          :integer          default(0)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
21
#  locked_at         :datetime
Stan Hu's avatar
Stan Hu committed
22
#  updated_by_id     :integer
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
23
#  merge_error       :string(255)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
24 25
#

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
26 27 28
require 'spec_helper'

describe MergeRequest do
29 30
  subject { create(:merge_request) }

31 32 33 34 35 36 37
  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') }

    it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
  end

38 39 40 41 42 43 44 45 46 47 48
  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

  describe 'validation' do
49 50
    it { is_expected.to validate_presence_of(:target_branch) }
    it { is_expected.to validate_presence_of(:source_branch) }
51 52
  end

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
  end
Andrey Kumanyaev's avatar
Andrey Kumanyaev committed
58

59 60 61 62 63 64 65 66 67
  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
68
  end
69 70

  describe "#mr_and_commit_notes" do
71
    let!(:merge_request) { create(:merge_request) }
72 73

    before do
74
      allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
75 76
      create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.project)
      create(:note, noteable: merge_request, project: merge_request.project)
77 78 79
    end

    it "should include notes for commits" do
80 81
      expect(merge_request.commits).not_to be_empty
      expect(merge_request.mr_and_commit_notes.count).to eq(2)
82
    end
83 84 85 86 87 88

    it "should include notes for commits from target project as well" do
      create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.target_project)
      expect(merge_request.commits).not_to be_empty
      expect(merge_request.mr_and_commit_notes.count).to eq(3)
    end
89
  end
90 91 92

  describe '#is_being_reassigned?' do
    it 'returns true if the merge_request assignee has changed' do
93
      subject.assignee = create(:user)
94
      expect(subject.is_being_reassigned?).to be_truthy
95 96
    end
    it 'returns false if the merge request assignee has not changed' do
97
      expect(subject.is_being_reassigned?).to be_falsey
98 99
    end
  end
100 101 102

  describe '#for_fork?' do
    it 'returns true if the merge request is for a fork' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
103 104
      subject.source_project = create(:project, namespace: create(:group))
      subject.target_project = create(:project, namespace: create(:group))
105

106
      expect(subject.for_fork?).to be_truthy
107
    end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
108

109
    it 'returns false if is not for a fork' do
110
      expect(subject.for_fork?).to be_falsey
111 112 113
    end
  end

114 115 116
  describe 'detection of issues to be closed' do
    let(:issue0) { create :issue, project: subject.project }
    let(:issue1) { create :issue, project: subject.project }
skv's avatar
skv committed
117 118 119
    let(:commit0) { double('commit0', closes_issues: [issue0]) }
    let(:commit1) { double('commit1', closes_issues: [issue0]) }
    let(:commit2) { double('commit2', closes_issues: [issue1]) }
120 121

    before do
122
      allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
123 124 125
    end

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

129
      expect(subject.closes_issues).to eq([issue0, issue1].sort_by(&:id))
130 131 132
    end

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

136
      expect(subject.closes_issues).to be_empty
137
    end
138 139 140

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

145
      expect(subject.closes_issues).to include(issue2)
146
    end
147 148
  end

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
  describe "#work_in_progress?" do
    it "detects the 'WIP ' prefix" do
      subject.title = "WIP #{subject.title}"
      expect(subject).to be_work_in_progress
    end

    it "detects the 'WIP: ' prefix" do
      subject.title = "WIP: #{subject.title}"
      expect(subject).to be_work_in_progress
    end

    it "detects the '[WIP] ' prefix" do
      subject.title = "[WIP] #{subject.title}"
      expect(subject).to be_work_in_progress
    end

    it "doesn't detect WIP for words starting with WIP" do
      subject.title = "Wipwap #{subject.title}"
      expect(subject).not_to be_work_in_progress
    end

    it "doesn't detect WIP by default" do
      expect(subject).not_to be_work_in_progress
    end
  end

175 176 177 178 179 180 181 182 183 184 185
  describe "#hook_attrs" do
    it "has all the required keys" do
      attrs = subject.hook_attrs
      attrs = attrs.to_h
      expect(attrs).to include(:source)
      expect(attrs).to include(:target)
      expect(attrs).to include(:last_commit)
      expect(attrs).to include(:work_in_progress)
    end
  end

186
  it_behaves_like 'an editable mentionable' do
187
    subject { create(:merge_request) }
188

189 190
    let(:backref_text) { "merge request #{subject.to_reference}" }
    let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
191
  end
Vinnie Okada's avatar
Vinnie Okada committed
192 193

  it_behaves_like 'a Taskable' do
194
    subject { create :merge_request, :simple }
Vinnie Okada's avatar
Vinnie Okada committed
195
  end
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

  describe '#ci_commit' do
    describe 'when the source project exists' do
      it 'returns the latest commit' do
        commit    = double(:commit, id: '123abc')
        ci_commit = double(:ci_commit)

        allow(subject).to receive(:last_commit).and_return(commit)

        expect(subject.source_project).to receive(:ci_commit).
          with('123abc').
          and_return(ci_commit)

        expect(subject.ci_commit).to eq(ci_commit)
      end
    end

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

        expect(subject.ci_commit).to be_nil
      end
    end
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
221
end