debian-mirror-gitlab/spec/models/project_spec.rb

1369 lines
44 KiB
Ruby
Raw Normal View History

2014-09-02 18:07:02 +05:30
require 'spec_helper'
2015-12-23 02:04:40 +05:30
describe Project, models: true do
2015-09-11 14:41:01 +05:30
describe 'associations' do
2015-04-26 12:48:37 +05:30
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) }
2016-08-24 12:49:21 +05:30
it { is_expected.to have_many(:users).through(:project_members) }
it { is_expected.to have_many(:requesters).dependent(:destroy) }
2015-04-26 12:48:37 +05:30
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) }
2015-12-23 02:04:40 +05:30
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:pipelines) }
2015-12-23 02:04:40 +05:30
it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:runner_projects) }
it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:environments).dependent(:destroy) }
it { is_expected.to have_many(:deployments).dependent(:destroy) }
2016-04-02 18:10:28 +05:30
it { is_expected.to have_many(:todos).dependent(:destroy) }
2016-08-24 12:49:21 +05:30
describe '#members & #requesters' do
let(:project) { create(:project) }
let(:requester) { create(:user) }
let(:developer) { create(:user) }
before do
project.request_access(requester)
project.team << [developer, :developer]
end
describe '#members' do
it 'includes members and exclude requesters' do
member_user_ids = project.members.pluck(:user_id)
expect(member_user_ids).to include(developer.id)
expect(member_user_ids).not_to include(requester.id)
end
end
describe '#requesters' do
it 'does not include requesters' do
requester_user_ids = project.requesters.pluck(:user_id)
expect(requester_user_ids).to include(requester.id)
expect(requester_user_ids).not_to include(developer.id)
end
end
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
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) }
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe 'validation' do
2014-09-02 18:07:02 +05:30
let!(:project) { create(:project) }
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) }
2015-09-11 14:41:01 +05:30
it { is_expected.to validate_length_of(:name).is_within(0..255) }
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).scoped_to(:namespace_id) }
2015-09-11 14:41:01 +05:30
it { is_expected.to validate_length_of(:path).is_within(0..255) }
it { is_expected.to validate_length_of(:description).is_within(0..2000) }
2015-04-26 12:48:37 +05:30
it { is_expected.to validate_presence_of(:creator) }
it { is_expected.to validate_presence_of(:namespace) }
2016-08-24 12:49:21 +05:30
it { is_expected.to validate_presence_of(:repository_storage) }
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
it 'should not allow new projects beyond user limits' do
2014-09-02 18:07:02 +05:30
project2 = build(:project)
2015-04-26 12:48:37 +05:30
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(/Personal project creation is not allowed/)
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe 'wiki path conflict' do
context "when the new path has been used by the wiki of other Project" do
it 'should have an error on the name attribute' do
new_project = build_stubbed(:project, namespace_id: project.namespace_id, path: "#{project.path}.wiki")
expect(new_project).not_to be_valid
expect(new_project.errors[:name].first).to eq('has already been taken')
end
end
context "when the new wiki path has been used by the path of other Project" do
it 'should have an error on the name attribute' do
project_with_wiki_suffix = create(:project, path: 'foo.wiki')
new_project = build_stubbed(:project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo')
expect(new_project).not_to be_valid
expect(new_project.errors[:name].first).to eq('has already been taken')
end
end
end
context 'repository storages inclussion' do
let(:project2) { build(:project, repository_storage: 'missing') }
before do
storages = { 'custom' => 'tmp/tests/custom_repositories' }
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
it "should not allow repository storages that don't match a label in the configuration" do
expect(project2).not_to be_valid
expect(project2.errors[:repository_storage].first).to match(/is not included in the list/)
end
end
it 'does not allow an invalid URI as import_url' do
project2 = build(:project, import_url: 'invalid://')
expect(project2).not_to be_valid
end
it 'does allow a valid URI as import_url' do
project2 = build(:project, import_url: 'ssh://test@gitlab.com/project.git')
expect(project2).to be_valid
end
it 'allows an empty URI' do
project2 = build(:project, import_url: '')
expect(project2).to be_valid
end
it 'does not produce import data on an empty URI' do
project2 = build(:project, import_url: '')
expect(project2.import_data).to be_nil
end
it 'does not produce import data on an invalid URI' do
project2 = build(:project, import_url: 'test://')
expect(project2.import_data).to be_nil
end
2014-09-02 18:07:02 +05:30
end
2016-04-02 18:10:28 +05:30
2016-06-02 11:05:42 +05:30
describe 'default_scope' do
it 'excludes projects pending deletion from the results' do
project = create(:empty_project)
create(:empty_project, pending_delete: true)
expect(Project.all).to eq [project]
end
end
2015-12-23 02:04:40 +05:30
describe 'project token' do
it 'should set an random token if none provided' do
project = FactoryGirl.create :empty_project, runners_token: ''
expect(project.runners_token).not_to eq('')
end
it 'should not set an random toke if one provided' do
project = FactoryGirl.create :empty_project, runners_token: 'my-token'
expect(project.runners_token).to eq('my-token')
end
end
2014-09-02 18:07:02 +05:30
2015-04-26 12:48:37 +05:30
describe 'Respond to' do
it { is_expected.to respond_to(:url_to_repo) }
it { is_expected.to respond_to(:repo_exists?) }
it { is_expected.to respond_to(:update_merge_requests) }
it { is_expected.to respond_to(:execute_hooks) }
it { is_expected.to respond_to(:owner) }
it { is_expected.to respond_to(:path_with_namespace) }
2014-09-02 18:07:02 +05:30
end
describe '#name_with_namespace' do
let(:project) { build_stubbed(:empty_project) }
it { expect(project.name_with_namespace).to eq "#{project.namespace.human_name} / #{project.name}" }
it { expect(project.human_name).to eq project.name_with_namespace }
end
2015-09-11 14:41:01 +05:30
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
2016-08-24 12:49:21 +05:30
describe '#repository_storage_path' do
let(:project) { create(:project, repository_storage: 'custom') }
before do
FileUtils.mkdir('tmp/tests/custom_repositories')
storages = { 'custom' => 'tmp/tests/custom_repositories' }
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
after do
FileUtils.rm_rf('tmp/tests/custom_repositories')
end
it 'returns the repository storage path' do
expect(project.repository_storage_path).to eq('tmp/tests/custom_repositories')
end
end
2015-04-26 12:48:37 +05:30
it 'should return valid url to repo' do
project = Project.new(path: 'somewhere')
expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe "#web_url" do
let(:project) { create(:empty_project, path: "somewhere") }
it 'returns the full web URL for this repo' do
expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.path}/somewhere")
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe "#web_url_without_protocol" do
let(:project) { create(:empty_project, path: "somewhere") }
it 'returns the web URL without the protocol for this repo' do
expect(project.web_url_without_protocol).to eq("#{Gitlab.config.gitlab.url.split('://')[1]}/#{project.namespace.path}/somewhere")
end
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
describe 'last_activity methods' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
let(:last_event) { double(created_at: Time.now) }
2015-04-26 12:48:37 +05:30
describe 'last_activity' do
it 'should alias last_activity to last_event' do
2015-09-11 14:41:01 +05:30
allow(project).to receive(:last_event).and_return(last_event)
2015-04-26 12:48:37 +05:30
expect(project.last_activity).to eq(last_event)
2014-09-02 18:07:02 +05:30
end
end
describe 'last_activity_date' do
it 'returns the creation date of the project\'s last event if present' do
2015-10-24 18:46:33 +05:30
create(:event, project: project)
2015-04-26 12:48:37 +05:30
expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i)
2014-09-02 18:07:02 +05:30
end
it 'returns the project\'s last update date if it has no events' do
2015-04-26 12:48:37 +05:30
expect(project.last_activity_date).to eq(project.updated_at)
2014-09-02 18:07:02 +05:30
end
end
end
2015-09-11 14:41:01 +05:30
describe '#get_issue' do
let(:project) { create(:empty_project) }
2015-12-23 02:04:40 +05:30
let!(:issue) { create(:issue, project: project) }
2015-09-11 14:41:01 +05:30
context 'with default issues tracker' do
it 'returns an issue' do
expect(project.get_issue(issue.iid)).to eq issue
end
2015-12-23 02:04:40 +05:30
it 'returns count of open issues' do
expect(project.open_issues_count).to eq(1)
end
2015-09-11 14:41:01 +05:30
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
2016-08-24 12:49:21 +05:30
describe '#update_merge_requests' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
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 }
2015-04-26 12:48:37 +05:30
it 'should close merge request if last commit from source branch was pushed to target branch' do
2014-09-02 18:07:02 +05:30
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user)
merge_request.reload
2015-04-26 12:48:37 +05:30
expect(merge_request.merged?).to be_truthy
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
it 'should update merge request commits with new one if pushed to source branch' do
2014-09-02 18:07:02 +05:30
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user)
merge_request.reload
2016-08-24 12:49:21 +05:30
expect(merge_request.diff_head_sha).to eq(commit_id)
2014-09-02 18:07:02 +05:30
end
end
2016-06-22 15:30:34 +05:30
describe '.find_with_namespace' do
2014-09-02 18:07:02 +05:30
context 'with namespace' do
before do
@group = create :group, name: 'gitlab'
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
2015-04-26 12:48:37 +05:30
it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
2015-10-24 18:46:33 +05:30
it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) }
2015-04-26 12:48:37 +05:30
it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
2014-09-02 18:07:02 +05:30
end
2016-06-22 15:30:34 +05:30
context 'when multiple projects using a similar name exist' do
let(:group) { create(:group, name: 'gitlab') }
let!(:project1) do
create(:empty_project, name: 'gitlab1', path: 'gitlab', namespace: group)
end
let!(:project2) do
create(:empty_project, name: 'gitlab2', path: 'GITLAB', namespace: group)
end
it 'returns the row where the path matches literally' do
expect(Project.find_with_namespace('gitlab/GITLAB')).to eq(project2)
end
end
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#to_param' do
2014-09-02 18:07:02 +05:30
context 'with namespace' do
before do
@group = create :group, name: 'gitlab'
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
2015-04-26 12:48:37 +05:30
it { expect(@project.to_param).to eq('gitlabhq') }
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#repository' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
2016-08-24 12:49:21 +05:30
it 'returns valid repo' do
2015-04-26 12:48:37 +05:30
expect(project.repository).to be_kind_of(Repository)
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#default_issues_tracker?' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
it "should be true if used internal tracker" do
2015-04-26 12:48:37 +05:30
expect(project.default_issues_tracker?).to be_truthy
2014-09-02 18:07:02 +05:30
end
it "should be false if used other tracker" do
2015-04-26 12:48:37 +05:30
expect(ext_project.default_issues_tracker?).to be_falsey
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#external_issue_tracker' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
context 'on existing projects with no value for has_external_issue_tracker' do
before(:each) do
project.update_column(:has_external_issue_tracker, nil)
ext_project.update_column(:has_external_issue_tracker, nil)
end
it 'updates the has_external_issue_tracker boolean' do
expect do
project.external_issue_tracker
end.to change { project.reload.has_external_issue_tracker }.to(false)
expect do
ext_project.external_issue_tracker
end.to change { ext_project.reload.has_external_issue_tracker }.to(true)
end
end
it 'returns nil and does not query services when there is no external issue tracker' do
project.build_missing_services
project.reload
expect(project).not_to receive(:services)
expect(project.external_issue_tracker).to eq(nil)
end
it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
ext_project.reload # Factory returns a project with changed attributes
ext_project.build_missing_services
ext_project.reload
expect(ext_project).to receive(:services).once.and_call_original
2.times { expect(ext_project.external_issue_tracker).to be_a_kind_of(RedmineService) }
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#cache_has_external_issue_tracker' do
let(:project) { create(:project) }
it 'stores true if there is any external_issue_tracker' do
services = double(:service, external_issue_trackers: [RedmineService.new])
expect(project).to receive(:services).and_return(services)
2014-09-02 18:07:02 +05:30
expect do
project.cache_has_external_issue_tracker
end.to change { project.has_external_issue_tracker}.to(true)
2014-09-02 18:07:02 +05:30
end
it 'stores false if there is no external_issue_tracker' do
services = double(:service, external_issue_trackers: [])
expect(project).to receive(:services).and_return(services)
2014-09-02 18:07:02 +05:30
expect do
project.cache_has_external_issue_tracker
end.to change { project.has_external_issue_tracker}.to(false)
2014-09-02 18:07:02 +05:30
end
end
2016-08-24 12:49:21 +05:30
describe '#external_wiki' do
let(:project) { create(:project) }
context 'with an active external wiki' do
before do
create(:service, project: project, type: 'ExternalWikiService', active: true)
project.external_wiki
end
it 'sets :has_external_wiki as true' do
expect(project.has_external_wiki).to be(true)
end
it 'sets :has_external_wiki as false if an external wiki service is destroyed later' do
expect(project.has_external_wiki).to be(true)
project.services.external_wikis.first.destroy
expect(project.has_external_wiki).to be(false)
end
end
context 'with an inactive external wiki' do
before do
create(:service, project: project, type: 'ExternalWikiService', active: false)
end
it 'sets :has_external_wiki as false' do
expect(project.has_external_wiki).to be(false)
end
end
context 'with no external wiki' do
before do
project.external_wiki
end
it 'sets :has_external_wiki as false' do
expect(project.has_external_wiki).to be(false)
end
it 'sets :has_external_wiki as true if an external wiki service is created later' do
expect(project.has_external_wiki).to be(false)
create(:service, project: project, type: 'ExternalWikiService', active: true)
expect(project.has_external_wiki).to be(true)
end
end
end
describe '#open_branches' do
2014-09-02 18:07:02 +05:30
let(:project) { create(:project) }
before do
project.protected_branches.create(name: 'master')
end
2015-04-26 12:48:37 +05:30
it { expect(project.open_branches.map(&:name)).to include('feature') }
it { expect(project.open_branches.map(&:name)).not_to include('master') }
2016-08-24 12:49:21 +05:30
it "includes branches matching a protected branch wildcard" do
expect(project.open_branches.map(&:name)).to include('feature')
create(:protected_branch, name: 'feat*', project: project)
expect(Project.find(project.id).open_branches.map(&:name)).to include('feature')
end
2014-09-02 18:07:02 +05:30
end
describe '#star_count' do
it 'counts stars from multiple users' do
user1 = create :user
user2 = create :user
project = create :project, :public
expect(project.star_count).to eq(0)
user1.toggle_star(project)
expect(project.reload.star_count).to eq(1)
user2.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(2)
user1.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(1)
user2.toggle_star(project)
project.reload
expect(project.reload.star_count).to eq(0)
end
it 'counts stars on the right project' do
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)
end
end
2015-04-26 12:48:37 +05:30
2016-08-24 12:49:21 +05:30
describe '#avatar_type' do
2015-04-26 12:48:37 +05:30
let(:project) { create(:project) }
it 'should be true if avatar is image' do
project.update_attribute(:avatar, 'uploads/avatar.png')
expect(project.avatar_type).to be_truthy
end
it 'should be false if avatar is html page' do
project.update_attribute(:avatar, 'uploads/avatar.html')
expect(project.avatar_type).to eq(['only images allowed'])
end
end
2016-08-24 12:49:21 +05:30
describe '#avatar_url' do
2015-04-26 12:48:37 +05:30
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
2016-06-02 11:05:42 +05:30
context 'when git repo is empty' do
let(:project) { create(:empty_project) }
it { should eq nil }
end
2015-04-26 12:48:37 +05:30
end
2015-10-24 18:46:33 +05:30
2016-08-24 12:49:21 +05:30
describe '#pipeline' do
2015-10-24 18:46:33 +05:30
let(:project) { create :project }
let(:pipeline) { create :ci_pipeline, project: project, ref: 'master' }
2016-06-02 11:05:42 +05:30
subject { project.pipeline(pipeline.sha, 'master') }
2015-10-24 18:46:33 +05:30
it { is_expected.to eq(pipeline) }
2016-06-02 11:05:42 +05:30
context 'return latest' do
let(:pipeline2) { create :ci_pipeline, project: project, ref: 'master' }
2016-06-02 11:05:42 +05:30
before do
pipeline
pipeline2
2016-06-02 11:05:42 +05:30
end
it { is_expected.to eq(pipeline2) }
2016-06-02 11:05:42 +05:30
end
2015-10-24 18:46:33 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#builds_enabled' do
2015-10-24 18:46:33 +05:30
let(:project) { create :project }
2015-11-26 14:37:03 +05:30
before { project.builds_enabled = true }
2015-10-24 18:46:33 +05:30
2015-11-26 14:37:03 +05:30
subject { project.builds_enabled }
it { expect(project.builds_enabled?).to be_truthy }
2015-10-24 18:46:33 +05:30
end
2016-08-24 12:49:21 +05:30
describe '.cached_count', caching: true do
let(:group) { create(:group, :public) }
let!(:project1) { create(:empty_project, :public, group: group) }
let!(:project2) { create(:empty_project, :public, group: group) }
it 'returns total project count' do
expect(Project).to receive(:count).once.and_call_original
3.times do
expect(Project.cached_count).to eq(2)
end
end
end
2015-10-24 18:46:33 +05:30
describe '.trending' do
2016-06-02 11:05:42 +05:30
let(:group) { create(:group, :public) }
2015-10-24 18:46:33 +05:30
let(:project1) { create(:empty_project, :public, group: group) }
let(:project2) { create(:empty_project, :public, group: group) }
before do
2.times do
create(:note_on_commit, project: project1)
end
create(:note_on_commit, project: project2)
end
describe 'without an explicit start date' do
subject { described_class.trending.to_a }
it 'sorts Projects by the amount of notes in descending order' do
expect(subject).to eq([project1, project2])
end
end
describe 'with an explicit start date' do
let(:date) { 2.months.ago }
subject { described_class.trending(date).to_a }
before do
2.times do
2015-12-23 02:04:40 +05:30
# Little fix for special issue related to Fractional Seconds support for MySQL.
# See: https://github.com/rails/rails/pull/14359/files
create(:note_on_commit, project: project2, created_at: date + 1)
2015-10-24 18:46:33 +05:30
end
end
it 'sorts Projects by the amount of notes in descending order' do
expect(subject).to eq([project2, project1])
end
end
end
2015-11-26 14:37:03 +05:30
describe '.visible_to_user' do
let!(:project) { create(:project, :private) }
let!(:user) { create(:user) }
subject { described_class.visible_to_user(user) }
describe 'when a user has access to a project' do
before do
project.team.add_user(user, Gitlab::Access::MASTER)
end
it { is_expected.to eq([project]) }
end
describe 'when a user does not have access to any projects' do
it { is_expected.to eq([]) }
end
end
2015-12-23 02:04:40 +05:30
2016-08-24 12:49:21 +05:30
context 'repository storage by default' do
let(:project) { create(:empty_project) }
subject { project.repository_storage }
before do
storages = { 'alternative_storage' => '/some/path' }
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
stub_application_setting(repository_storage: 'alternative_storage')
allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(true)
end
it { is_expected.to eq('alternative_storage') }
end
2015-12-23 02:04:40 +05:30
context 'shared runners by default' do
let(:project) { create(:empty_project) }
subject { project.shared_runners_enabled }
context 'are enabled' do
before { stub_application_setting(shared_runners_enabled: true) }
it { is_expected.to be_truthy }
end
context 'are disabled' do
before { stub_application_setting(shared_runners_enabled: false) }
it { is_expected.to be_falsey }
end
end
2016-08-24 12:49:21 +05:30
describe '#any_runners' do
2015-12-23 02:04:40 +05:30
let(:project) { create(:empty_project, shared_runners_enabled: shared_runners_enabled) }
2016-04-02 18:10:28 +05:30
let(:specific_runner) { create(:ci_runner) }
let(:shared_runner) { create(:ci_runner, :shared) }
2015-12-23 02:04:40 +05:30
context 'for shared runners disabled' do
let(:shared_runners_enabled) { false }
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
it 'there are no runners available' do
expect(project.any_runners?).to be_falsey
end
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
it 'there is a specific runner' do
project.runners << specific_runner
expect(project.any_runners?).to be_truthy
end
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
it 'there is a shared runner, but they are prohibited to use' do
shared_runner
expect(project.any_runners?).to be_falsey
end
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
it 'checks the presence of specific runner' do
project.runners << specific_runner
expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
end
end
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
context 'for shared runners enabled' do
let(:shared_runners_enabled) { true }
2016-04-02 18:10:28 +05:30
2015-12-23 02:04:40 +05:30
it 'there is a shared runner' do
shared_runner
expect(project.any_runners?).to be_truthy
end
it 'checks the presence of shared runner' do
shared_runner
expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
end
end
end
describe '#visibility_level_allowed?' do
2016-06-02 11:05:42 +05:30
let(:project) { create(:project, :internal) }
context 'when checking on non-forked project' do
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy }
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy }
it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_truthy }
end
context 'when checking on forked project' do
2016-06-02 11:05:42 +05:30
let(:project) { create(:project, :internal) }
let(:forked_project) { create(:project, forked_from_project: project) }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy }
it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey }
end
2016-06-02 11:05:42 +05:30
end
describe '.search' do
let(:project) { create(:project, description: 'kitten mittens') }
it 'returns projects with a matching name' do
expect(described_class.search(project.name)).to eq([project])
end
it 'returns projects with a partially matching name' do
expect(described_class.search(project.name[0..2])).to eq([project])
end
it 'returns projects with a matching name regardless of the casing' do
expect(described_class.search(project.name.upcase)).to eq([project])
end
it 'returns projects with a matching description' do
expect(described_class.search(project.description)).to eq([project])
end
it 'returns projects with a partially matching description' do
expect(described_class.search('kitten')).to eq([project])
end
it 'returns projects with a matching description regardless of the casing' do
expect(described_class.search('KITTEN')).to eq([project])
end
it 'returns projects with a matching path' do
expect(described_class.search(project.path)).to eq([project])
end
2016-06-02 11:05:42 +05:30
it 'returns projects with a partially matching path' do
expect(described_class.search(project.path[0..2])).to eq([project])
end
it 'returns projects with a matching path regardless of the casing' do
expect(described_class.search(project.path.upcase)).to eq([project])
end
it 'returns projects with a matching namespace name' do
expect(described_class.search(project.namespace.name)).to eq([project])
end
it 'returns projects with a partially matching namespace name' do
expect(described_class.search(project.namespace.name[0..2])).to eq([project])
end
it 'returns projects with a matching namespace name regardless of the casing' do
expect(described_class.search(project.namespace.name.upcase)).to eq([project])
end
it 'returns projects when eager loading namespaces' do
relation = described_class.all.includes(:namespace)
expect(relation.search(project.namespace.name)).to eq([project])
end
end
2016-04-02 18:10:28 +05:30
describe '#rename_repo' do
let(:project) { create(:project) }
let(:gitlab_shell) { Gitlab::Shell.new }
before do
# Project#gitlab_shell returns a new instance of Gitlab::Shell on every
# call. This makes testing a bit easier.
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
allow(project).to receive(:previous_changes).and_return('path' => ['foo'])
2016-06-02 11:05:42 +05:30
end
2016-04-02 18:10:28 +05:30
2016-06-02 11:05:42 +05:30
it 'renames a repository' do
2016-04-02 18:10:28 +05:30
ns = project.namespace_dir
expect(gitlab_shell).to receive(:mv_repository).
ordered.
2016-08-24 12:49:21 +05:30
with(project.repository_storage_path, "#{ns}/foo", "#{ns}/#{project.path}").
2016-04-02 18:10:28 +05:30
and_return(true)
expect(gitlab_shell).to receive(:mv_repository).
ordered.
2016-08-24 12:49:21 +05:30
with(project.repository_storage_path, "#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki").
2016-04-02 18:10:28 +05:30
and_return(true)
expect_any_instance_of(SystemHooksService).
to receive(:execute_hooks_for).
with(project, :rename)
expect_any_instance_of(Gitlab::UploadsTransfer).
to receive(:rename_project).
with('foo', project.path, ns)
expect(project).to receive(:expire_caches_before_rename)
project.rename_repo
end
2016-06-02 11:05:42 +05:30
context 'container registry with tags' do
before do
stub_container_registry_config(enabled: true)
stub_container_registry_tags('tag')
end
subject { project.rename_repo }
it { expect{subject}.to raise_error(Exception) }
end
2016-04-02 18:10:28 +05:30
end
describe '#expire_caches_before_rename' do
let(:project) { create(:project) }
let(:repo) { double(:repo, exists?: true) }
let(:wiki) { double(:wiki, exists?: true) }
it 'expires the caches of the repository and wiki' do
allow(Repository).to receive(:new).
with('foo', project).
and_return(repo)
allow(Repository).to receive(:new).
with('foo.wiki', project).
and_return(wiki)
2016-06-02 11:05:42 +05:30
expect(repo).to receive(:before_delete)
expect(wiki).to receive(:before_delete)
2016-04-02 18:10:28 +05:30
project.expire_caches_before_rename('foo')
end
end
2016-06-02 11:05:42 +05:30
describe '.search_by_title' do
let(:project) { create(:project, name: 'kittens') }
it 'returns projects with a matching name' do
expect(described_class.search_by_title(project.name)).to eq([project])
end
it 'returns projects with a partially matching name' do
expect(described_class.search_by_title('kitten')).to eq([project])
end
it 'returns projects with a matching name regardless of the casing' do
expect(described_class.search_by_title('KITTENS')).to eq([project])
end
end
context 'when checking projects from groups' do
let(:private_group) { create(:group, visibility_level: 0) }
let(:internal_group) { create(:group, visibility_level: 10) }
let(:private_project) { create :project, :private, group: private_group }
let(:internal_project) { create :project, :internal, group: internal_group }
context 'when group is private project can not be internal' do
it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey }
end
context 'when group is internal project can not be public' do
it { expect(internal_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey }
end
end
describe '#create_repository' do
let(:project) { create(:project) }
let(:shell) { Gitlab::Shell.new }
before do
allow(project).to receive(:gitlab_shell).and_return(shell)
end
context 'using a regular repository' do
it 'creates the repository' do
expect(shell).to receive(:add_repository).
2016-08-24 12:49:21 +05:30
with(project.repository_storage_path, project.path_with_namespace).
2016-06-02 11:05:42 +05:30
and_return(true)
expect(project.repository).to receive(:after_create)
expect(project.create_repository).to eq(true)
end
it 'adds an error if the repository could not be created' do
expect(shell).to receive(:add_repository).
2016-08-24 12:49:21 +05:30
with(project.repository_storage_path, project.path_with_namespace).
2016-06-02 11:05:42 +05:30
and_return(false)
expect(project.repository).not_to receive(:after_create)
expect(project.create_repository).to eq(false)
expect(project.errors).not_to be_empty
end
end
context 'using a forked repository' do
it 'does nothing' do
expect(project).to receive(:forked?).and_return(true)
expect(shell).not_to receive(:add_repository)
project.create_repository
end
end
end
describe '#protected_branch?' do
let(:project) { create(:empty_project) }
2016-08-24 12:49:21 +05:30
it 'returns true when the branch matches a protected branch via direct match' do
2016-06-02 11:05:42 +05:30
project.protected_branches.create!(name: 'foo')
expect(project.protected_branch?('foo')).to eq(true)
end
2016-08-24 12:49:21 +05:30
it 'returns true when the branch matches a protected branch via wildcard match' do
project.protected_branches.create!(name: 'production/*')
expect(project.protected_branch?('production/some-branch')).to eq(true)
end
it 'returns false when the branch does not match a protected branch via direct match' do
2016-06-02 11:05:42 +05:30
expect(project.protected_branch?('foo')).to eq(false)
end
2016-08-24 12:49:21 +05:30
it 'returns false when the branch does not match a protected branch via wildcard match' do
project.protected_branches.create!(name: 'production/*')
expect(project.protected_branch?('staging/some-branch')).to eq(false)
end
end
describe "#developers_can_push_to_protected_branch?" do
let(:project) { create(:empty_project) }
context "when the branch matches a protected branch via direct match" do
it "returns true if 'Developers can Push' is turned on" do
create(:protected_branch, name: "production", project: project, developers_can_push: true)
expect(project.developers_can_push_to_protected_branch?('production')).to be true
end
it "returns false if 'Developers can Push' is turned off" do
create(:protected_branch, name: "production", project: project, developers_can_push: false)
expect(project.developers_can_push_to_protected_branch?('production')).to be false
end
end
context "when the branch matches a protected branch via wilcard match" do
it "returns true if 'Developers can Push' is turned on" do
create(:protected_branch, name: "production/*", project: project, developers_can_push: true)
expect(project.developers_can_push_to_protected_branch?('production/some-branch')).to be true
end
it "returns false if 'Developers can Push' is turned off" do
create(:protected_branch, name: "production/*", project: project, developers_can_push: false)
expect(project.developers_can_push_to_protected_branch?('production/some-branch')).to be false
end
end
context "when the branch does not match a protected branch" do
it "returns false" do
create(:protected_branch, name: "production/*", project: project, developers_can_push: true)
expect(project.developers_can_push_to_protected_branch?('staging/some-branch')).to be false
end
end
2016-06-02 11:05:42 +05:30
end
describe '#container_registry_path_with_namespace' do
let(:project) { create(:empty_project, path: 'PROJECT') }
subject { project.container_registry_path_with_namespace }
it { is_expected.not_to eq(project.path_with_namespace) }
it { is_expected.to eq(project.path_with_namespace.downcase) }
end
2016-06-02 11:05:42 +05:30
describe '#container_registry_repository' do
let(:project) { create(:empty_project) }
before { stub_container_registry_config(enabled: true) }
subject { project.container_registry_repository }
it { is_expected.not_to be_nil }
2016-06-02 11:05:42 +05:30
end
describe '#container_registry_repository_url' do
let(:project) { create(:empty_project) }
subject { project.container_registry_repository_url }
before { stub_container_registry_config(**registry_settings) }
context 'for enabled registry' do
let(:registry_settings) do
{
enabled: true,
host_port: 'example.com',
}
end
it { is_expected.not_to be_nil }
2016-06-02 11:05:42 +05:30
end
context 'for disabled registry' do
let(:registry_settings) do
{
enabled: false
}
end
it { is_expected.to be_nil }
end
end
describe '#has_container_registry_tags?' do
let(:project) { create(:empty_project) }
subject { project.has_container_registry_tags? }
context 'for enabled registry' do
before { stub_container_registry_config(enabled: true) }
context 'with tags' do
before { stub_container_registry_tags('test', 'test2') }
it { is_expected.to be_truthy }
end
context 'when no tags' do
before { stub_container_registry_tags }
it { is_expected.to be_falsey }
end
end
context 'for disabled registry' do
before { stub_container_registry_config(enabled: false) }
it { is_expected.to be_falsey }
end
end
2016-08-24 12:49:21 +05:30
describe '#latest_successful_builds_for' do
def create_pipeline(status = 'success')
create(:ci_pipeline, project: project,
sha: project.commit.sha,
ref: project.default_branch,
status: status)
end
def create_build(new_pipeline = pipeline, name = 'test')
create(:ci_build, :success, :artifacts,
pipeline: new_pipeline,
status: new_pipeline.status,
name: name)
end
let(:project) { create(:project) }
let(:pipeline) { create_pipeline }
context 'with many builds' do
it 'gives the latest builds from latest pipeline' do
pipeline1 = create_pipeline
pipeline2 = create_pipeline
build1_p2 = create_build(pipeline2, 'test')
create_build(pipeline1, 'test')
create_build(pipeline1, 'test2')
build2_p2 = create_build(pipeline2, 'test2')
latest_builds = project.latest_successful_builds_for
expect(latest_builds).to contain_exactly(build2_p2, build1_p2)
end
end
context 'with succeeded pipeline' do
let!(:build) { create_build }
context 'standalone pipeline' do
it 'returns builds for ref for default_branch' do
builds = project.latest_successful_builds_for
expect(builds).to contain_exactly(build)
end
it 'returns empty relation if the build cannot be found' do
builds = project.latest_successful_builds_for('TAIL')
expect(builds).to be_kind_of(ActiveRecord::Relation)
expect(builds).to be_empty
end
end
context 'with some pending pipeline' do
before do
create_build(create_pipeline('pending'))
end
it 'gives the latest build from latest pipeline' do
latest_build = project.latest_successful_builds_for
expect(latest_build).to contain_exactly(build)
end
end
end
context 'with pending pipeline' do
before do
pipeline.update(status: 'pending')
create_build(pipeline)
end
it 'returns empty relation' do
builds = project.latest_successful_builds_for
expect(builds).to be_kind_of(ActiveRecord::Relation)
expect(builds).to be_empty
end
end
end
describe '#add_import_job' do
context 'forked' do
let(:forked_project_link) { create(:forked_project_link) }
let(:forked_from_project) { forked_project_link.forked_from_project }
let(:project) { forked_project_link.forked_to_project }
it 'schedules a RepositoryForkWorker job' do
expect(RepositoryForkWorker).to receive(:perform_async).
with(project.id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace, project.namespace.path)
project.add_import_job
end
end
context 'not forked' do
let(:project) { create(:project) }
it 'schedules a RepositoryImportWorker job' do
expect(RepositoryImportWorker).to receive(:perform_async).with(project.id)
project.add_import_job
end
end
end
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
expect(Project.where_paths_in([])).to eq([])
end
end
context 'without any valid paths' do
it 'returns an empty relation' do
expect(Project.where_paths_in(%w[foo])).to eq([])
end
end
context 'with valid paths' do
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
it 'returns the projects matching the paths' do
projects = Project.where_paths_in([project1.path_with_namespace,
project2.path_with_namespace])
expect(projects).to contain_exactly(project1, project2)
end
it 'returns projects regardless of the casing of paths' do
projects = Project.where_paths_in([project1.path_with_namespace.upcase,
project2.path_with_namespace.upcase])
expect(projects).to contain_exactly(project1, project2)
end
end
end
2016-08-24 12:49:21 +05:30
describe 'authorized_for_user' do
let(:group) { create(:group) }
let(:developer) { create(:user) }
let(:master) { create(:user) }
let(:personal_project) { create(:project, namespace: developer.namespace) }
let(:group_project) { create(:project, namespace: group) }
let(:members_project) { create(:project) }
let(:shared_project) { create(:project) }
before do
group.add_master(master)
group.add_developer(developer)
members_project.team << [developer, :developer]
members_project.team << [master, :master]
create(:project_group_link, project: shared_project, group: group)
end
it 'returns false for no user' do
expect(personal_project.authorized_for_user?(nil)).to be(false)
end
it 'returns true for personal projects of the user' do
expect(personal_project.authorized_for_user?(developer)).to be(true)
end
it 'returns true for projects of groups the user is a member of' do
expect(group_project.authorized_for_user?(developer)).to be(true)
end
it 'returns true for projects for which the user is a member of' do
expect(members_project.authorized_for_user?(developer)).to be(true)
end
it 'returns true for projects shared on a group the user is a member of' do
expect(shared_project.authorized_for_user?(developer)).to be(true)
end
it 'checks for the correct minimum level access' do
expect(group_project.authorized_for_user?(developer, Gitlab::Access::MASTER)).to be(false)
expect(group_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
expect(members_project.authorized_for_user?(developer, Gitlab::Access::MASTER)).to be(false)
expect(members_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
expect(shared_project.authorized_for_user?(developer, Gitlab::Access::MASTER)).to be(false)
expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
end
end
2014-09-02 18:07:02 +05:30
end