project_spec.rb 13.3 KB
Newer Older
1 2 3 4
# == Schema Information
#
# Table name: projects
#
D
Dmitriy Zaporozhets 已提交
5
#  id                     :integer          not null, primary key
6 7 8
#  name                   :string(255)
#  path                   :string(255)
#  description            :text
D
Dmitriy Zaporozhets 已提交
9 10
#  created_at             :datetime
#  updated_at             :datetime
D
Dmitriy Zaporozhets 已提交
11
#  creator_id             :integer
D
Dmitriy Zaporozhets 已提交
12 13 14 15
#  issues_enabled         :boolean          default(TRUE), not null
#  wall_enabled           :boolean          default(TRUE), not null
#  merge_requests_enabled :boolean          default(TRUE), not null
#  wiki_enabled           :boolean          default(TRUE), not null
D
Dmitriy Zaporozhets 已提交
16
#  namespace_id           :integer
D
Dmitriy Zaporozhets 已提交
17
#  issues_tracker         :string(255)      default("gitlab"), not null
D
Dmitriy Zaporozhets 已提交
18
#  issues_tracker_id      :string(255)
D
Dmitriy Zaporozhets 已提交
19
#  snippets_enabled       :boolean          default(TRUE), not null
20
#  last_activity_at       :datetime
D
Dmitriy Zaporozhets 已提交
21
#  import_url             :string(255)
22
#  visibility_level       :integer          default(0), not null
23
#  archived               :boolean          default(FALSE), not null
D
Dmitriy Zaporozhets 已提交
24
#  import_status          :string(255)
D
Dmitriy Zaporozhets 已提交
25 26
#  repository_size        :float            default(0.0)
#  star_count             :integer          default(0), not null
D
Dmitriy Zaporozhets 已提交
27 28
#  import_type            :string(255)
#  import_source          :string(255)
29
#  avatar                 :string(255)
30 31
#

G
gitlabhq 已提交
32 33 34
require 'spec_helper'

describe Project do
35
  describe 'associations' do
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    it { is_expected.to belong_to(:group) }
    it { is_expected.to belong_to(:namespace) }
    it { is_expected.to belong_to(:creator).class_name('User') }
    it { is_expected.to have_many(:users) }
    it { is_expected.to have_many(:events).dependent(:destroy) }
    it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
    it { is_expected.to have_many(:issues).dependent(:destroy) }
    it { is_expected.to have_many(:milestones).dependent(:destroy) }
    it { is_expected.to have_many(:project_members).dependent(:destroy) }
    it { is_expected.to have_many(:notes).dependent(:destroy) }
    it { is_expected.to have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) }
    it { is_expected.to have_many(:deploy_keys_projects).dependent(:destroy) }
    it { is_expected.to have_many(:deploy_keys) }
    it { is_expected.to have_many(:hooks).dependent(:destroy) }
    it { is_expected.to have_many(:protected_branches).dependent(:destroy) }
    it { is_expected.to have_one(:forked_project_link).dependent(:destroy) }
    it { is_expected.to have_one(:slack_service).dependent(:destroy) }
    it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
    it { is_expected.to have_one(:asana_service).dependent(:destroy) }
G
gitlabhq 已提交
55 56
  end

57 58 59 60 61 62 63 64
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Gitlab::ConfigHelper) }
    it { is_expected.to include_module(Gitlab::ShellAdapter) }
    it { is_expected.to include_module(Gitlab::VisibilityLevel) }
    it { is_expected.to include_module(Referable) }
    it { is_expected.to include_module(Sortable) }
65 66
  end

67
  describe 'validation' do
68 69
    let!(:project) { create(:project) }

70 71 72
    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) }
    it { is_expected.to ensure_length_of(:name).is_within(0..255) }
73

74 75 76 77 78 79 80
    it { is_expected.to validate_presence_of(:path) }
    it { is_expected.to validate_uniqueness_of(:path).scoped_to(:namespace_id) }
    it { is_expected.to ensure_length_of(:path).is_within(0..255) }
    it { is_expected.to ensure_length_of(:description).is_within(0..2000) }
    it { is_expected.to validate_presence_of(:creator) }
    it { is_expected.to ensure_length_of(:issues_tracker_id).is_within(0..255) }
    it { is_expected.to validate_presence_of(:namespace) }
81

82
    it 'should not allow new projects beyond user limits' do
83
      project2 = build(:project)
84 85 86
      allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
      expect(project2).not_to be_valid
      expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
87
    end
G
gitlabhq 已提交
88 89
  end

90
  describe 'Respond to' do
91 92 93 94 95 96 97 98
    it { is_expected.to respond_to(:url_to_repo) }
    it { is_expected.to respond_to(:repo_exists?) }
    it { is_expected.to respond_to(:satellite) }
    it { is_expected.to respond_to(:update_merge_requests) }
    it { is_expected.to respond_to(:execute_hooks) }
    it { is_expected.to respond_to(:name_with_namespace) }
    it { is_expected.to respond_to(:owner) }
    it { is_expected.to respond_to(:path_with_namespace) }
G
gitlabhq 已提交
99 100
  end

101 102 103 104 105 106 107 108
  describe '#to_reference' do
    let(:project) { create(:empty_project) }

    it 'returns a String reference to the object' do
      expect(project.to_reference).to eq project.path_with_namespace
    end
  end

109 110
  it 'should return valid url to repo' do
    project = Project.new(path: 'somewhere')
111
    expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
G
gitlabhq 已提交
112 113
  end

114 115
  it 'returns the full web URL for this repo' do
    project = Project.new(path: 'somewhere')
116
    expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/somewhere")
A
Ariejan de Vroom 已提交
117 118
  end

119 120
  it 'returns the web URL without the protocol for this repo' do
    project = Project.new(path: 'somewhere')
121
    expect(project.web_url_without_protocol).to eq("#{Gitlab.config.gitlab.url.split('://')[1]}/somewhere")
122 123
  end

124
  describe 'last_activity methods' do
I
Izaak Alpert 已提交
125
    let(:project) { create(:project) }
126
    let(:last_event) { double(created_at: Time.now) }
G
gitlabhq 已提交
127

128 129
    describe 'last_activity' do
      it 'should alias last_activity to last_event' do
130
        project.stub(last_event: last_event)
131
        expect(project.last_activity).to eq(last_event)
132
      end
G
gitlabhq 已提交
133 134
    end

135 136
    describe 'last_activity_date' do
      it 'returns the creation date of the project\'s last event if present' do
A
Andrey Kumanyaev 已提交
137
        last_activity_event = create(:event, project: project)
138
        expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i)
139
      end
140

141
      it 'returns the project\'s last update date if it has no events' do
142
        expect(project.last_activity_date).to eq(project.updated_at)
143
      end
144 145
    end
  end
146

147 148 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 175 176 177 178 179 180 181 182 183 184 185 186 187 188
  describe '#get_issue' do
    let(:project) { create(:empty_project) }
    let(:issue)   { create(:issue, project: project) }

    context 'with default issues tracker' do
      it 'returns an issue' do
        expect(project.get_issue(issue.iid)).to eq issue
      end

      it 'returns nil when no issue found' do
        expect(project.get_issue(999)).to be_nil
      end
    end

    context 'with external issues tracker' do
      before do
        allow(project).to receive(:default_issues_tracker?).and_return(false)
      end

      it 'returns an ExternalIssue' do
        issue = project.get_issue('FOO-1234')
        expect(issue).to be_kind_of(ExternalIssue)
        expect(issue.iid).to eq 'FOO-1234'
        expect(issue.project).to eq project
      end
    end
  end

  describe '#issue_exists?' do
    let(:project) { create(:empty_project) }

    it 'is truthy when issue exists' do
      expect(project).to receive(:get_issue).and_return(double)
      expect(project.issue_exists?(1)).to be_truthy
    end

    it 'is falsey when issue does not exist' do
      expect(project).to receive(:get_issue).and_return(nil)
      expect(project.issue_exists?(1)).to be_falsey
    end
  end

189
  describe :update_merge_requests do
D
Dmitriy Zaporozhets 已提交
190
    let(:project) { create(:project) }
191 192 193 194
    let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
    let(:key) { create(:key, user_id: project.owner.id) }
    let(:prev_commit_id) { merge_request.commits.last.id }
    let(:commit_id) { merge_request.commits.first.id }
195

196
    it 'should close merge request if last commit from source branch was pushed to target branch' do
197 198
      project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user)
      merge_request.reload
199
      expect(merge_request.merged?).to be_truthy
200 201
    end

202
    it 'should update merge request commits with new one if pushed to source branch' do
203 204
      project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user)
      merge_request.reload
205
      expect(merge_request.last_commit.id).to eq(commit_id)
206 207
    end
  end
208 209 210 211 212

  describe :find_with_namespace do
    context 'with namespace' do
      before do
        @group = create :group, name: 'gitlab'
D
Dmitriy Zaporozhets 已提交
213
        @project = create(:project, name: 'gitlabhq', namespace: @group)
214 215
      end

216 217
      it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
      it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
218 219 220 221 222 223 224
    end
  end

  describe :to_param do
    context 'with namespace' do
      before do
        @group = create :group, name: 'gitlab'
D
Dmitriy Zaporozhets 已提交
225
        @project = create(:project, name: 'gitlabhq', namespace: @group)
226 227
      end

V
Vinnie Okada 已提交
228
      it { expect(@project.to_param).to eq('gitlabhq') }
229 230
    end
  end
D
Dmitriy Zaporozhets 已提交
231

232
  describe :repository do
D
Dmitriy Zaporozhets 已提交
233 234
    let(:project) { create(:project) }

235
    it 'should return valid repo' do
236
      expect(project.repository).to be_kind_of(Repository)
D
Dmitriy Zaporozhets 已提交
237 238
    end
  end
239

240
  describe :default_issues_tracker? do
241 242 243 244
    let(:project) { create(:project) }
    let(:ext_project) { create(:redmine_project) }

    it "should be true if used internal tracker" do
245
      expect(project.default_issues_tracker?).to be_truthy
246 247 248
    end

    it "should be false if used other tracker" do
249
      expect(ext_project.default_issues_tracker?).to be_falsey
250 251 252
    end
  end

A
Andrew8xx8 已提交
253 254 255 256
  describe :can_have_issues_tracker_id? do
    let(:project) { create(:project) }
    let(:ext_project) { create(:redmine_project) }

257
    it 'should be true for projects with external issues tracker if issues enabled' do
258
      expect(ext_project.can_have_issues_tracker_id?).to be_truthy
259
    end
A
Andrew8xx8 已提交
260

261
    it 'should be false for projects with internal issue tracker if issues enabled' do
262
      expect(project.can_have_issues_tracker_id?).to be_falsey
A
Andrew8xx8 已提交
263 264
    end

265
    it 'should be always false if issues disabled' do
A
Andrew8xx8 已提交
266 267 268
      project.issues_enabled = false
      ext_project.issues_enabled = false

269 270
      expect(project.can_have_issues_tracker_id?).to be_falsey
      expect(ext_project.can_have_issues_tracker_id?).to be_falsey
A
Andrew8xx8 已提交
271 272
    end
  end
273 274

  describe :open_branches do
D
Dmitriy Zaporozhets 已提交
275
    let(:project) { create(:project) }
276 277 278 279 280

    before do
      project.protected_branches.create(name: 'master')
    end

281 282
    it { expect(project.open_branches.map(&:name)).to include('feature') }
    it { expect(project.open_branches.map(&:name)).not_to include('master') }
283
  end
C
Ciro Santilli 已提交
284

285 286
  describe '#star_count' do
    it 'counts stars from multiple users' do
C
Ciro Santilli 已提交
287 288 289 290 291
      user1 = create :user
      user2 = create :user
      project = create :project, :public

      expect(project.star_count).to eq(0)
292

C
Ciro Santilli 已提交
293
      user1.toggle_star(project)
294 295
      expect(project.reload.star_count).to eq(1)

C
Ciro Santilli 已提交
296
      user2.toggle_star(project)
297 298 299
      project.reload
      expect(project.reload.star_count).to eq(2)

C
Ciro Santilli 已提交
300
      user1.toggle_star(project)
301 302 303
      project.reload
      expect(project.reload.star_count).to eq(1)

C
Ciro Santilli 已提交
304
      user2.toggle_star(project)
305 306 307 308
      project.reload
      expect(project.reload.star_count).to eq(0)
    end

309
    it 'counts stars on the right project' do
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
      user = create :user
      project1 = create :project, :public
      project2 = create :project, :public

      expect(project1.star_count).to eq(0)
      expect(project2.star_count).to eq(0)

      user.toggle_star(project1)
      project1.reload
      project2.reload
      expect(project1.star_count).to eq(1)
      expect(project2.star_count).to eq(0)

      user.toggle_star(project1)
      project1.reload
      project2.reload
      expect(project1.star_count).to eq(0)
      expect(project2.star_count).to eq(0)

      user.toggle_star(project2)
      project1.reload
      project2.reload
      expect(project1.star_count).to eq(0)
      expect(project2.star_count).to eq(1)

      user.toggle_star(project2)
      project1.reload
      project2.reload
      expect(project1.star_count).to eq(0)
      expect(project2.star_count).to eq(0)
C
Ciro Santilli 已提交
340
    end
341 342 343 344 345 346 347 348 349 350 351

    it 'is decremented when an upvoter account is deleted' do
      user = create :user
      project = create :project, :public
      user.toggle_star(project)
      project.reload
      expect(project.star_count).to eq(1)
      user.destroy
      project.reload
      expect(project.star_count).to eq(0)
    end
C
Ciro Santilli 已提交
352
  end
353 354 355 356 357 358

  describe :avatar_type do
    let(:project) { create(:project) }

    it 'should be true if avatar is image' do
      project.update_attribute(:avatar, 'uploads/avatar.png')
359
      expect(project.avatar_type).to be_truthy
360 361 362 363
    end

    it 'should be false if avatar is html page' do
      project.update_attribute(:avatar, 'uploads/avatar.html')
364
      expect(project.avatar_type).to eq(['only images allowed'])
365 366
    end
  end
S
sue445 已提交
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

  describe :avatar_url do
    subject { project.avatar_url }

    let(:project) { create(:project) }

    context 'When avatar file is uploaded' do
      before do
        project.update_columns(avatar: 'uploads/avatar.png')
        allow(project.avatar).to receive(:present?) { true }
      end

      let(:avatar_path) do
        "/uploads/project/avatar/#{project.id}/uploads/avatar.png"
      end

      it { should eq "http://localhost#{avatar_path}" }
    end

    context 'When avatar file in git' do
      before do
        allow(project).to receive(:avatar_in_git) { true }
      end

      let(:avatar_path) do
        "/#{project.namespace.name}/#{project.path}/avatar"
      end

      it { should eq "http://localhost#{avatar_path}" }
    end
  end
G
gitlabhq 已提交
398
end