merge_request_spec.rb 9.8 KB
Newer Older
D
Dmitriy Zaporozhets 已提交
1 2 3 4
# == Schema Information
#
# Table name: merge_requests
#
S
Stan Hu 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#  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)
#  created_at                :datetime
#  updated_at                :datetime
#  milestone_id              :integer
#  state                     :string(255)
#  merge_status              :string(255)
#  target_project_id         :integer          not null
#  iid                       :integer
#  description               :text
#  position                  :integer          default(0)
#  locked_at                 :datetime
#  updated_by_id             :integer
#  merge_error               :string(255)
#  merge_params              :text
#  merge_when_build_succeeds :boolean          default(FALSE), not null
#  merge_user_id             :integer
D
Dmitriy Zaporozhets 已提交
27 28
#

D
Dmitriy Zaporozhets 已提交
29 30
require 'spec_helper'

D
Douwe Maan 已提交
31
describe MergeRequest, models: true do
32 33
  subject { create(:merge_request) }

R
Robert Speicher 已提交
34 35 36
  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') }
37
    it { is_expected.to belong_to(:merge_user).class_name("User") }
R
Robert Speicher 已提交
38 39 40
    it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
  end

41 42 43 44 45 46 47 48 49 50 51
  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
52 53
    it { is_expected.to validate_presence_of(:target_branch) }
    it { is_expected.to validate_presence_of(:source_branch) }
Z
Zeger-Jan van de Weg 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

    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 已提交
72 73
  end

R
Robert Speicher 已提交
74
  describe 'respond to' do
75 76 77
    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?) }
78 79
    it { is_expected.to respond_to(:merge_params) }
    it { is_expected.to respond_to(:merge_when_build_succeeds) }
80
  end
A
Andrey Kumanyaev 已提交
81

82 83 84 85 86 87 88 89 90
  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
91
  end
92 93

  describe "#mr_and_commit_notes" do
94
    let!(:merge_request) { create(:merge_request) }
95 96

    before do
97
      allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
D
Dmitriy Zaporozhets 已提交
98 99
      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)
100 101 102
    end

    it "should include notes for commits" do
103 104
      expect(merge_request.commits).not_to be_empty
      expect(merge_request.mr_and_commit_notes.count).to eq(2)
105
    end
106 107 108 109 110 111

    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
112
  end
113 114 115

  describe '#is_being_reassigned?' do
    it 'returns true if the merge_request assignee has changed' do
116
      subject.assignee = create(:user)
117
      expect(subject.is_being_reassigned?).to be_truthy
118 119
    end
    it 'returns false if the merge request assignee has not changed' do
120
      expect(subject.is_being_reassigned?).to be_falsey
121 122
    end
  end
I
Izaak Alpert 已提交
123 124 125

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

129
      expect(subject.for_fork?).to be_truthy
I
Izaak Alpert 已提交
130
    end
D
Dmitriy Zaporozhets 已提交
131

I
Izaak Alpert 已提交
132
    it 'returns false if is not for a fork' do
133
      expect(subject.for_fork?).to be_falsey
I
Izaak Alpert 已提交
134 135 136
    end
  end

137 138 139
  describe 'detection of issues to be closed' do
    let(:issue0) { create :issue, project: subject.project }
    let(:issue1) { create :issue, project: subject.project }
S
skv 已提交
140 141 142
    let(:commit0) { double('commit0', closes_issues: [issue0]) }
    let(:commit1) { double('commit1', closes_issues: [issue0]) }
    let(:commit2) { double('commit2', closes_issues: [issue1]) }
143 144

    before do
145
      allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
146 147 148
    end

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

152
      expect(subject.closes_issues).to eq([issue0, issue1].sort_by(&:id))
153 154 155
    end

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

159
      expect(subject.closes_issues).to be_empty
160
    end
161 162 163

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

168
      expect(subject.closes_issues).to include(issue2)
169
    end
D
Drew Blessing 已提交
170 171 172 173 174 175 176 177 178 179 180

    context 'for a project with JIRA integration' do
      let(:issue0) { JiraIssue.new('JIRA-123', subject.project) }
      let(:issue1) { JiraIssue.new('FOOBAR-4567', subject.project) }

      it 'returns sorted JiraIssues' do
        allow(subject.project).to receive_messages(default_branch: subject.target_branch)

        expect(subject.closes_issues).to eq([issue0, issue1])
      end
    end
181 182
  end

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  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

Z
Zeger-Jan van de Weg 已提交
209
  describe '#can_remove_source_branch?' do
Z
Zeger-Jan van de Weg 已提交
210 211
    let(:user) { create(:user) }
    let(:user2) { create(:user) }
212 213 214 215

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

Z
Zeger-Jan van de Weg 已提交
216 217 218 219
      subject.source_branch = "feature"
      subject.target_branch = "master"
      subject.save!
    end
220

Z
Zeger-Jan van de Weg 已提交
221 222
    it "can't be removed when its a protected branch" do
      allow(subject.source_project).to receive(:protected_branch?).and_return(true)
223 224 225 226
      expect(subject.can_remove_source_branch?(user)).to be_falsey
    end

    it "cant remove a root ref" do
Z
Zeger-Jan van de Weg 已提交
227 228
      subject.source_branch = "master"
      subject.target_branch = "feature"
229 230 231 232

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

Z
Zeger-Jan van de Weg 已提交
233 234 235 236 237 238
    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

    it "is can be removed in all other cases" do
      expect(subject.can_remove_source_branch?(user)).to be_truthy
239 240 241
    end
  end

242
  describe "#reset_merge_when_build_succeeds" do
Z
Zeger-Jan van de Weg 已提交
243 244
    let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user) }

245 246 247 248 249 250 251 252
    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
    end
  end

253 254 255 256 257 258 259 260 261 262 263
  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

264
  it_behaves_like 'an editable mentionable' do
265
    subject { create(:merge_request) }
266

267 268
    let(:backref_text) { "merge request #{subject.to_reference}" }
    let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
269
  end
V
Vinnie Okada 已提交
270 271

  it_behaves_like 'a Taskable' do
272
    subject { create :merge_request, :simple }
V
Vinnie Okada 已提交
273
  end
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298

  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
D
Dmitriy Zaporozhets 已提交
299
end