summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/ability_spec.rb13
-rw-r--r--spec/models/build_spec.rb8
-rw-r--r--spec/models/ci/build_spec.rb60
-rw-r--r--spec/models/ci/pipeline_spec.rb30
-rw-r--r--spec/models/commit_range_spec.rb10
-rw-r--r--spec/models/concerns/awardable_spec.rb10
-rw-r--r--spec/models/concerns/has_status_spec.rb (renamed from spec/models/concerns/statuseable_spec.rb)6
-rw-r--r--spec/models/concerns/project_features_compatibility_spec.rb25
-rw-r--r--spec/models/members/project_member_spec.rb7
-rw-r--r--spec/models/merge_request_diff_spec.rb21
-rw-r--r--spec/models/merge_request_spec.rb141
-rw-r--r--spec/models/network/graph_spec.rb12
-rw-r--r--spec/models/note_spec.rb22
-rw-r--r--spec/models/project_feature_spec.rb91
-rw-r--r--spec/models/project_security_spec.rb112
-rw-r--r--spec/models/project_spec.rb85
-rw-r--r--spec/models/repository_spec.rb48
-rw-r--r--spec/models/user_spec.rb13
18 files changed, 530 insertions, 184 deletions
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index 853f6943cef..1bdf005c823 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -218,4 +218,17 @@ describe Ability, lib: true do
end
end
end
+
+ describe '.project_disabled_features_rules' do
+ let(:project) { create(:project, wiki_access_level: ProjectFeature::DISABLED) }
+
+ subject { described_class.allowed(project.owner, project) }
+
+ context 'wiki named abilities' do
+ it 'disables wiki abilities if the project has no wiki' do
+ expect(project).to receive(:has_external_wiki?).and_return(false)
+ expect(subject).not_to include(:read_wiki, :create_wiki, :update_wiki, :admin_wiki)
+ end
+ end
+ end
end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index ee2c3d04984..c45c2635cf4 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -948,15 +948,17 @@ describe Ci::Build, models: true do
before { build.run! }
it 'returns false' do
- expect(build.retryable?).to be false
+ expect(build).not_to be_retryable
end
end
context 'when build is finished' do
- before { build.success! }
+ before do
+ build.success!
+ end
it 'returns true' do
- expect(build.retryable?).to be true
+ expect(build).to be_retryable
end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 36d10636ae9..bce18b4e99e 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -19,4 +19,64 @@ describe Ci::Build, models: true do
expect(build.trace).to eq(test_trace)
end
end
+
+ describe '#has_trace_file?' do
+ context 'when there is no trace' do
+ it { expect(build.has_trace_file?).to be_falsey }
+ it { expect(build.trace).to be_nil }
+ end
+
+ context 'when there is a trace' do
+ context 'when trace is stored in file' do
+ let(:build_with_trace) { create(:ci_build, :trace) }
+
+ it { expect(build_with_trace.has_trace_file?).to be_truthy }
+ it { expect(build_with_trace.trace).to eq('BUILD TRACE') }
+ end
+
+ context 'when trace is stored in old file' do
+ before do
+ allow(build.project).to receive(:ci_id).and_return(999)
+ allow(File).to receive(:exist?).with(build.path_to_trace).and_return(false)
+ allow(File).to receive(:exist?).with(build.old_path_to_trace).and_return(true)
+ allow(File).to receive(:read).with(build.old_path_to_trace).and_return(test_trace)
+ end
+
+ it { expect(build.has_trace_file?).to be_truthy }
+ it { expect(build.trace).to eq(test_trace) }
+ end
+
+ context 'when trace is stored in DB' do
+ before do
+ allow(build.project).to receive(:ci_id).and_return(nil)
+ allow(build).to receive(:read_attribute).with(:trace).and_return(test_trace)
+ allow(File).to receive(:exist?).with(build.path_to_trace).and_return(false)
+ allow(File).to receive(:exist?).with(build.old_path_to_trace).and_return(false)
+ end
+
+ it { expect(build.has_trace_file?).to be_falsey }
+ it { expect(build.trace).to eq(test_trace) }
+ end
+ end
+ end
+
+ describe '#trace_file_path' do
+ context 'when trace is stored in file' do
+ before do
+ allow(build).to receive(:has_trace_file?).and_return(true)
+ allow(build).to receive(:has_old_trace_file?).and_return(false)
+ end
+
+ it { expect(build.trace_file_path).to eq(build.path_to_trace) }
+ end
+
+ context 'when trace is stored in old file' do
+ before do
+ allow(build).to receive(:has_trace_file?).and_return(true)
+ allow(build).to receive(:has_old_trace_file?).and_return(true)
+ end
+
+ it { expect(build.trace_file_path).to eq(build.old_path_to_trace) }
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 721b20e0cb2..598df576001 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -195,6 +195,36 @@ describe Ci::Pipeline, models: true do
end
end
+ context 'with non-empty project' do
+ let(:project) { create(:project) }
+
+ let(:pipeline) do
+ create(:ci_pipeline,
+ project: project,
+ ref: project.default_branch,
+ sha: project.commit.sha)
+ end
+
+ describe '#latest?' do
+ context 'with latest sha' do
+ it 'returns true' do
+ expect(pipeline).to be_latest
+ end
+ end
+
+ context 'with not latest sha' do
+ before do
+ pipeline.update(
+ sha: project.commit("#{project.default_branch}~1").sha)
+ end
+
+ it 'returns false' do
+ expect(pipeline).not_to be_latest
+ end
+ end
+ end
+ end
+
describe '#manual_actions' do
subject { pipeline.manual_actions }
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index 384a38ebc69..c41359b55a3 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -76,16 +76,6 @@ describe CommitRange, models: true do
end
end
- describe '#reference_title' do
- it 'returns the correct String for three-dot ranges' do
- expect(range.reference_title).to eq "Commits #{full_sha_from} through #{full_sha_to}"
- end
-
- it 'returns the correct String for two-dot ranges' do
- expect(range2.reference_title).to eq "Commits #{full_sha_from}^ through #{full_sha_to}"
- end
- end
-
describe '#to_param' do
it 'includes the correct keys' do
expect(range.to_param.keys).to eq %i(from to)
diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb
index a371c4a18a9..de791abdf3d 100644
--- a/spec/models/concerns/awardable_spec.rb
+++ b/spec/models/concerns/awardable_spec.rb
@@ -45,4 +45,14 @@ describe Issue, "Awardable" do
expect { issue.toggle_award_emoji("thumbsdown", award_emoji.user) }.to change { AwardEmoji.count }.by(-1)
end
end
+
+ describe 'querying award_emoji on an Awardable' do
+ let(:issue) { create(:issue) }
+
+ it 'sorts in ascending fashion' do
+ create_list(:award_emoji, 3, awardable: issue)
+
+ expect(issue.award_emoji).to eq issue.award_emoji.sort_by(&:id)
+ end
+ end
end
diff --git a/spec/models/concerns/statuseable_spec.rb b/spec/models/concerns/has_status_spec.rb
index 8e0a2a2cbde..e118432d098 100644
--- a/spec/models/concerns/statuseable_spec.rb
+++ b/spec/models/concerns/has_status_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Statuseable do
+describe HasStatus do
before do
@object = Object.new
- @object.extend(Statuseable::ClassMethods)
+ @object.extend(HasStatus::ClassMethods)
end
describe '.status' do
@@ -12,7 +12,7 @@ describe Statuseable do
end
subject { @object.status }
-
+
shared_examples 'build status summary' do
context 'all successful' do
let(:statuses) { Array.new(2) { create(type, status: :success) } }
diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb
new file mode 100644
index 00000000000..5363aea4d22
--- /dev/null
+++ b/spec/models/concerns/project_features_compatibility_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe ProjectFeaturesCompatibility do
+ let(:project) { create(:project) }
+ let(:features) { %w(issues wiki builds merge_requests snippets) }
+
+ # We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table
+ # All those fields got moved to a new table called project_feature and are now integers instead of booleans
+ # This spec tests if the described concern makes sure parameters received by the API are correctly parsed to the new table
+ # So we can keep it compatible
+
+ it "converts fields from 'true' to ProjectFeature::ENABLED" do
+ features.each do |feature|
+ project.update_attribute("#{feature}_enabled".to_sym, "true")
+ expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::ENABLED)
+ end
+ end
+
+ it "converts fields from 'false' to ProjectFeature::DISABLED" do
+ features.each do |feature|
+ project.update_attribute("#{feature}_enabled".to_sym, "false")
+ expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::DISABLED)
+ end
+ end
+end
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 913d74645a7..be57957b569 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -71,9 +71,6 @@ describe ProjectMember, models: true do
describe :import_team do
before do
- @abilities = Six.new
- @abilities << Ability
-
@project_1 = create :project
@project_2 = create :project
@@ -92,8 +89,8 @@ describe ProjectMember, models: true do
it { expect(@project_2.users).to include(@user_1) }
it { expect(@project_2.users).to include(@user_2) }
- it { expect(@abilities.allowed?(@user_1, :create_project, @project_2)).to be_truthy }
- it { expect(@abilities.allowed?(@user_2, :read_project, @project_2)).to be_truthy }
+ it { expect(Ability.allowed?(@user_1, :create_project, @project_2)).to be_truthy }
+ it { expect(Ability.allowed?(@user_2, :read_project, @project_2)).to be_truthy }
end
describe 'project 1 should not be changed' do
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 29f7396f862..e5b185dc3f6 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -1,6 +1,27 @@
require 'spec_helper'
describe MergeRequestDiff, models: true do
+ describe 'create new record' do
+ subject { create(:merge_request).merge_request_diff }
+
+ it { expect(subject).to be_valid }
+ it { expect(subject).to be_persisted }
+ it { expect(subject.commits.count).to eq(5) }
+ it { expect(subject.diffs.count).to eq(8) }
+ it { expect(subject.head_commit_sha).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ it { expect(subject.base_commit_sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
+ it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') }
+ end
+
+ describe '#latest' do
+ let!(:mr) { create(:merge_request, :with_diffs) }
+ let!(:first_diff) { mr.merge_request_diff }
+ let!(:last_diff) { mr.create_merge_request_diff }
+
+ it { expect(last_diff.latest?).to be_truthy }
+ it { expect(first_diff.latest?).to be_falsey }
+ end
+
describe '#diffs' do
let(:mr) { create(:merge_request, :with_diffs) }
let(:mr_diff) { mr.merge_request_diff }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 64c56d922ff..5bf3b8e609e 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -9,7 +9,7 @@ describe MergeRequest, models: true 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 belong_to(:merge_user).class_name("User") }
- it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
+ it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) }
end
describe 'modules' do
@@ -159,7 +159,7 @@ describe MergeRequest, models: true do
context 'when there are MR diffs' do
it 'delegates to the MR diffs' do
- merge_request.merge_request_diff = MergeRequestDiff.new
+ merge_request.save
expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(hash_including(options))
@@ -316,7 +316,7 @@ describe MergeRequest, models: true do
end
it "can be removed if the last commit is the head of the source branch" do
- allow(subject.source_project).to receive(:commit).and_return(subject.diff_head_commit)
+ allow(subject).to receive(:source_branch_head).and_return(subject.diff_head_commit)
expect(subject.can_remove_source_branch?(user)).to be_truthy
end
@@ -477,8 +477,8 @@ describe MergeRequest, models: true do
allow(subject).to receive(:diff_head_sha).and_return('123abc')
- expect(subject.source_project).to receive(:pipeline).
- with('123abc', 'master').
+ expect(subject.source_project).to receive(:pipeline_for).
+ with('master', '123abc').
and_return(pipeline)
expect(subject.pipeline).to eq(pipeline)
@@ -721,12 +721,15 @@ describe MergeRequest, models: true do
let(:commit) { subject.project.commit(sample_commit.id) }
- it "reloads the diff content" do
- expect(subject.merge_request_diff).to receive(:reload_content)
-
+ it "does not change existing merge request diff" do
+ expect(subject.merge_request_diff).not_to receive(:save_git_content)
subject.reload_diff
end
+ it "creates new merge request diff" do
+ expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1)
+ end
+
it "executs diff cache service" do
expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject)
@@ -736,13 +739,15 @@ describe MergeRequest, models: true do
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
+ allow(subject).to receive(:create_merge_request_diff) do
+ subject.merge_request_diffs.create(
+ base_commit_sha: commit.parent_id,
+ start_commit_sha: commit.parent_id,
+ head_commit_sha: commit.sha
+ )
+
+ subject.merge_request_diff(true)
end
expect(Notes::DiffPositionUpdateService).to receive(:new).with(
@@ -752,14 +757,31 @@ describe MergeRequest, models: true do
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(Notes::DiffPositionUpdateService).to receive(:execute).with(note)
expect_any_instance_of(DiffNote).to receive(:save).once
subject.reload_diff
end
end
+ describe '#branch_merge_base_commit' do
+ context 'source and target branch exist' do
+ it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') }
+ it { expect(subject.branch_merge_base_commit).to be_a(Commit) }
+ end
+
+ context 'when the target branch does not exist' do
+ before do
+ subject.project.repository.raw_repository.delete_branch(subject.target_branch)
+ end
+
+ it 'returns nil' do
+ expect(subject.branch_merge_base_commit).to be_nil
+ end
+ end
+ end
+
describe "#diff_sha_refs" do
context "with diffs" do
subject { create(:merge_request, :with_diffs) }
@@ -890,6 +912,19 @@ describe MergeRequest, models: true do
expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
end
+ it 'returns a falsey value when the MR is marked as having conflicts, but has none' do
+ merge_request = create_merge_request('master')
+
+ expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
+ end
+
+ it 'returns a falsey value when the MR has a missing ref after a force push' do
+ merge_request = create_merge_request('conflict-resolvable')
+ allow(merge_request.conflicts).to receive(:merge_index).and_raise(Rugged::OdbError)
+
+ expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
+ end
+
it 'returns a falsey value when the MR does not support new diff notes' do
merge_request = create_merge_request('conflict-resolvable')
merge_request.merge_request_diff.update_attributes(start_commit_sha: nil)
@@ -927,4 +962,80 @@ describe MergeRequest, models: true do
expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_truthy
end
end
+
+ describe "#forked_source_project_missing?" do
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:project, forked_from_project: project) }
+ let(:user) { create(:user) }
+ let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) }
+
+ context "when the fork exists" do
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: fork_project,
+ target_project: project)
+ end
+
+ it { expect(merge_request.forked_source_project_missing?).to be_falsey }
+ end
+
+ context "when the source project is the same as the target project" do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ it { expect(merge_request.forked_source_project_missing?).to be_falsey }
+ end
+
+ context "when the fork does not exist" do
+ let(:merge_request) do
+ create(:merge_request,
+ source_project: fork_project,
+ target_project: project)
+ end
+
+ it "returns true" do
+ unlink_project.execute
+ merge_request.reload
+
+ expect(merge_request.forked_source_project_missing?).to be_truthy
+ end
+ end
+ end
+
+ describe "#closed_without_fork?" do
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:project, forked_from_project: project) }
+ let(:user) { create(:user) }
+ let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) }
+
+ context "when the merge request is closed" do
+ let(:closed_merge_request) do
+ create(:closed_merge_request,
+ source_project: fork_project,
+ target_project: project)
+ end
+
+ it "returns false if the fork exist" do
+ expect(closed_merge_request.closed_without_fork?).to be_falsey
+ end
+
+ it "returns true if the fork does not exist" do
+ unlink_project.execute
+ closed_merge_request.reload
+
+ expect(closed_merge_request.closed_without_fork?).to be_truthy
+ end
+ end
+
+ context "when the merge request is open" do
+ let(:open_merge_request) do
+ create(:merge_request,
+ source_project: fork_project,
+ target_project: project)
+ end
+
+ it "returns false" do
+ expect(open_merge_request.closed_without_fork?).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb
new file mode 100644
index 00000000000..b76513d2a3c
--- /dev/null
+++ b/spec/models/network/graph_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Network::Graph, models: true do
+ let(:project) { create(:project) }
+ let!(:note_on_commit) { create(:note_on_commit, project: project) }
+
+ it '#initialize' do
+ graph = described_class.new(project, 'refs/heads/master', project.repository.commit, nil)
+
+ expect(graph.notes).to eq( { note_on_commit.commit_id => 1 } )
+ end
+end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index ef2747046b9..e6b6e7c0634 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -85,8 +85,6 @@ describe Note, models: true do
@u1 = create(:user)
@u2 = create(:user)
@u3 = create(:user)
- @abilities = Six.new
- @abilities << Ability
end
describe 'read' do
@@ -95,9 +93,9 @@ describe Note, models: true do
@p2.project_members.create(user: @u3, access_level: ProjectMember::GUEST)
end
- it { expect(@abilities.allowed?(@u1, :read_note, @p1)).to be_falsey }
- it { expect(@abilities.allowed?(@u2, :read_note, @p1)).to be_truthy }
- it { expect(@abilities.allowed?(@u3, :read_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u1, :read_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u2, :read_note, @p1)).to be_truthy }
+ it { expect(Ability.allowed?(@u3, :read_note, @p1)).to be_falsey }
end
describe 'write' do
@@ -106,9 +104,9 @@ describe Note, models: true do
@p2.project_members.create(user: @u3, access_level: ProjectMember::DEVELOPER)
end
- it { expect(@abilities.allowed?(@u1, :create_note, @p1)).to be_falsey }
- it { expect(@abilities.allowed?(@u2, :create_note, @p1)).to be_truthy }
- it { expect(@abilities.allowed?(@u3, :create_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u1, :create_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u2, :create_note, @p1)).to be_truthy }
+ it { expect(Ability.allowed?(@u3, :create_note, @p1)).to be_falsey }
end
describe 'admin' do
@@ -118,9 +116,9 @@ describe Note, models: true do
@p2.project_members.create(user: @u3, access_level: ProjectMember::MASTER)
end
- it { expect(@abilities.allowed?(@u1, :admin_note, @p1)).to be_falsey }
- it { expect(@abilities.allowed?(@u2, :admin_note, @p1)).to be_truthy }
- it { expect(@abilities.allowed?(@u3, :admin_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u1, :admin_note, @p1)).to be_falsey }
+ it { expect(Ability.allowed?(@u2, :admin_note, @p1)).to be_truthy }
+ it { expect(Ability.allowed?(@u3, :admin_note, @p1)).to be_falsey }
end
end
@@ -225,7 +223,7 @@ describe Note, models: true do
let(:note) do
create :note,
noteable: ext_issue, project: ext_proj,
- note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+ note: "Mentioned in issue #{private_issue.to_reference(ext_proj)}",
system: true
end
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
new file mode 100644
index 00000000000..8d554a01be5
--- /dev/null
+++ b/spec/models/project_feature_spec.rb
@@ -0,0 +1,91 @@
+require 'spec_helper'
+
+describe ProjectFeature do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ describe '#feature_available?' do
+ let(:features) { %w(issues wiki builds merge_requests snippets) }
+
+ context 'when features are disabled' do
+ it "returns false" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::DISABLED)
+ expect(project.feature_available?(:issues, user)).to eq(false)
+ end
+ end
+ end
+
+ context 'when features are enabled only for team members' do
+ it "returns false when user is not a team member" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE)
+ expect(project.feature_available?(:issues, user)).to eq(false)
+ end
+ end
+
+ it "returns true when user is a team member" do
+ project.team << [user, :developer]
+
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE)
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+
+ it "returns true when user is a member of project group" do
+ group = create(:group)
+ project = create(:project, namespace: group)
+ group.add_developer(user)
+
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE)
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+
+ it "returns true if user is an admin" do
+ user.update_attribute(:admin, true)
+
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE)
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+ end
+
+ context 'when feature is enabled for everyone' do
+ it "returns true" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::ENABLED)
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+ end
+ end
+
+ describe '#*_enabled?' do
+ let(:features) { %w(wiki builds merge_requests) }
+
+ it "returns false when feature is disabled" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::DISABLED)
+ expect(project.public_send("#{feature}_enabled?")).to eq(false)
+ end
+ end
+
+ it "returns true when feature is enabled only for team members" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE)
+ expect(project.public_send("#{feature}_enabled?")).to eq(true)
+ end
+ end
+
+ it "returns true when feature is enabled for everyone" do
+ features.each do |feature|
+ project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::ENABLED)
+ expect(project.public_send("#{feature}_enabled?")).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/models/project_security_spec.rb b/spec/models/project_security_spec.rb
deleted file mode 100644
index 36379074ea0..00000000000
--- a/spec/models/project_security_spec.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-require 'spec_helper'
-
-describe Project, models: true do
- describe 'authorization' do
- before do
- @p1 = create(:project)
-
- @u1 = create(:user)
- @u2 = create(:user)
- @u3 = create(:user)
- @u4 = @p1.owner
-
- @abilities = Six.new
- @abilities << Ability
- end
-
- let(:guest_actions) { Ability.project_guest_rules }
- let(:report_actions) { Ability.project_report_rules }
- let(:dev_actions) { Ability.project_dev_rules }
- let(:master_actions) { Ability.project_master_rules }
- let(:owner_actions) { Ability.project_owner_rules }
-
- describe "Non member rules" do
- it "denies for non-project users any actions" do
- owner_actions.each do |action|
- expect(@abilities.allowed?(@u1, action, @p1)).to be_falsey
- end
- end
- end
-
- describe "Guest Rules" do
- before do
- @p1.project_members.create(project: @p1, user: @u2, access_level: ProjectMember::GUEST)
- end
-
- it "allows for project user any guest actions" do
- guest_actions.each do |action|
- expect(@abilities.allowed?(@u2, action, @p1)).to be_truthy
- end
- end
- end
-
- describe "Report Rules" do
- before do
- @p1.project_members.create(project: @p1, user: @u2, access_level: ProjectMember::REPORTER)
- end
-
- it "allows for project user any report actions" do
- report_actions.each do |action|
- expect(@abilities.allowed?(@u2, action, @p1)).to be_truthy
- end
- end
- end
-
- describe "Developer Rules" do
- before do
- @p1.project_members.create(project: @p1, user: @u2, access_level: ProjectMember::REPORTER)
- @p1.project_members.create(project: @p1, user: @u3, access_level: ProjectMember::DEVELOPER)
- end
-
- it "denies for developer master-specific actions" do
- [dev_actions - report_actions].each do |action|
- expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
- end
- end
-
- it "allows for project user any dev actions" do
- dev_actions.each do |action|
- expect(@abilities.allowed?(@u3, action, @p1)).to be_truthy
- end
- end
- end
-
- describe "Master Rules" do
- before do
- @p1.project_members.create(project: @p1, user: @u2, access_level: ProjectMember::DEVELOPER)
- @p1.project_members.create(project: @p1, user: @u3, access_level: ProjectMember::MASTER)
- end
-
- it "denies for developer master-specific actions" do
- [master_actions - dev_actions].each do |action|
- expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
- end
- end
-
- it "allows for project user any master actions" do
- master_actions.each do |action|
- expect(@abilities.allowed?(@u3, action, @p1)).to be_truthy
- end
- end
- end
-
- describe "Owner Rules" do
- before do
- @p1.project_members.create(project: @p1, user: @u2, access_level: ProjectMember::DEVELOPER)
- @p1.project_members.create(project: @p1, user: @u3, access_level: ProjectMember::MASTER)
- end
-
- it "denies for masters admin-specific actions" do
- [owner_actions - master_actions].each do |action|
- expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
- end
- end
-
- it "allows for project owner any admin actions" do
- owner_actions.each do |action|
- expect(@abilities.allowed?(@u4, action, @p1)).to be_truthy
- end
- end
- end
- end
-end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index d1f3a815290..4a41fafb84d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -247,7 +247,7 @@ describe Project, models: true do
end
end
- describe "#new_issue_address" do
+ xdescribe "#new_issue_address" do
let(:project) { create(:empty_project, path: "somewhere") }
let(:user) { create(:user) }
@@ -506,6 +506,18 @@ describe Project, models: true do
end
end
+ describe '#has_wiki?' do
+ let(:no_wiki_project) { build(:project, wiki_enabled: false, has_external_wiki: false) }
+ let(:wiki_enabled_project) { build(:project) }
+ let(:external_wiki_project) { build(:project, has_external_wiki: true) }
+
+ it 'returns true if project is wiki enabled or has external wiki' do
+ expect(wiki_enabled_project).to have_wiki
+ expect(external_wiki_project).to have_wiki
+ expect(no_wiki_project).not_to have_wiki
+ end
+ end
+
describe '#external_wiki' do
let(:project) { create(:project) }
@@ -685,31 +697,43 @@ describe Project, models: true do
end
end
- describe '#pipeline' do
- let(:project) { create :project }
- let(:pipeline) { create :ci_pipeline, project: project, ref: 'master' }
-
- subject { project.pipeline(pipeline.sha, 'master') }
+ describe '#pipeline_for' do
+ let(:project) { create(:project) }
+ let!(:pipeline) { create_pipeline }
- it { is_expected.to eq(pipeline) }
+ shared_examples 'giving the correct pipeline' do
+ it { is_expected.to eq(pipeline) }
- context 'return latest' do
- let(:pipeline2) { create :ci_pipeline, project: project, ref: 'master' }
+ context 'return latest' do
+ let!(:pipeline2) { create_pipeline }
- before do
- pipeline
- pipeline2
+ it { is_expected.to eq(pipeline2) }
end
+ end
+
+ context 'with explicit sha' do
+ subject { project.pipeline_for('master', pipeline.sha) }
+
+ it_behaves_like 'giving the correct pipeline'
+ end
+
+ context 'with implicit sha' do
+ subject { project.pipeline_for('master') }
+
+ it_behaves_like 'giving the correct pipeline'
+ end
- it { is_expected.to eq(pipeline2) }
+ def create_pipeline
+ create(:ci_pipeline,
+ project: project,
+ ref: 'master',
+ sha: project.commit('master').sha)
end
end
describe '#builds_enabled' do
let(:project) { create :project }
- before { project.builds_enabled = true }
-
subject { project.builds_enabled }
it { expect(project.builds_enabled?).to be_truthy }
@@ -1442,4 +1466,35 @@ describe Project, models: true do
expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
end
end
+
+ describe 'change_head' do
+ let(:project) { create(:project) }
+
+ it 'calls the before_change_head method' do
+ expect(project.repository).to receive(:before_change_head)
+ project.change_head(project.default_branch)
+ end
+
+ it 'creates the new reference with rugged' do
+ expect(project.repository.rugged.references).to receive(:create).with('HEAD',
+ "refs/heads/#{project.default_branch}",
+ force: true)
+ project.change_head(project.default_branch)
+ end
+
+ it 'copies the gitattributes' do
+ expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch)
+ project.change_head(project.default_branch)
+ end
+
+ it 'expires the avatar cache' do
+ expect(project.repository).to receive(:expire_avatar_cache).with(project.default_branch)
+ project.change_head(project.default_branch)
+ end
+
+ it 'reloads the default branch' do
+ expect(project).to receive(:reload_default_branch)
+ project.change_head(project.default_branch)
+ end
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 1fea50ad42c..afc7dc5db81 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -382,6 +382,24 @@ describe Repository, models: true do
end
end
+ describe '#find_branch' do
+ it 'loads a branch with a fresh repo' do
+ expect(Gitlab::Git::Repository).to receive(:new).twice.and_call_original
+
+ 2.times do
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
+
+ it 'loads a branch with a cached repo' do
+ expect(Gitlab::Git::Repository).to receive(:new).once.and_call_original
+
+ 2.times do
+ expect(repository.find_branch('feature', fresh_repo: false)).not_to be_nil
+ end
+ end
+ end
+
describe '#rm_branch' do
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
let(:blank_sha) { '0000000000000000000000000000000000000000' }
@@ -425,31 +443,32 @@ describe Repository, models: true do
describe '#commit_with_hooks' do
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
+ let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev
context 'when pre hooks were successful' do
before do
expect_any_instance_of(GitHooksService).to receive(:execute).
- with(user, repository.path_to_repo, old_rev, sample_commit.id, 'refs/heads/feature').
+ with(user, repository.path_to_repo, old_rev, new_rev, 'refs/heads/feature').
and_yield.and_return(true)
end
it 'runs without errors' do
expect do
- repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ repository.commit_with_hooks(user, 'feature') { new_rev }
end.not_to raise_error
end
it 'ensures the autocrlf Git option is set to :input' do
expect(repository).to receive(:update_autocrlf_option)
- repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ repository.commit_with_hooks(user, 'feature') { new_rev }
end
context "when the branch wasn't empty" do
it 'updates the head' do
expect(repository.find_branch('feature').target.id).to eq(old_rev)
- repository.commit_with_hooks(user, 'feature') { sample_commit.id }
- expect(repository.find_branch('feature').target.id).to eq(sample_commit.id)
+ repository.commit_with_hooks(user, 'feature') { new_rev }
+ expect(repository.find_branch('feature').target.id).to eq(new_rev)
end
end
end
@@ -459,7 +478,7 @@ describe Repository, models: true do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do
- repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ repository.commit_with_hooks(user, 'feature') { new_rev }
end.to raise_error(GitHooksService::PreReceiveError)
end
end
@@ -467,6 +486,7 @@ describe Repository, models: true do
context 'when target branch is different from source branch' do
before do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, ''])
+ allow(repository).to receive(:update_ref!)
end
it 'expires branch cache' do
@@ -477,7 +497,7 @@ describe Repository, models: true do
expect(repository).to receive(:expire_has_visible_content_cache)
expect(repository).to receive(:expire_branch_count_cache)
- repository.commit_with_hooks(user, 'new-feature') { sample_commit.id }
+ repository.commit_with_hooks(user, 'new-feature') { new_rev }
end
end
@@ -1250,4 +1270,18 @@ describe Repository, models: true do
File.delete(path)
end
end
+
+ describe '#update_ref!' do
+ it 'can create a ref' do
+ repository.update_ref!('refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA)
+
+ expect(repository.find_branch('foobar')).not_to be_nil
+ end
+
+ it 'raises CommitError when the ref update fails' do
+ expect do
+ repository.update_ref!('refs/heads/master', 'refs/heads/master', Gitlab::Git::BLANK_SHA)
+ end.to raise_error(Repository::CommitError)
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 51e4780e2b1..a1770d96f83 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -920,6 +920,16 @@ describe User, models: true do
expect(subject.recent_push).to eq(nil)
end
+
+ it "includes push events on any of the provided projects" do
+ expect(subject.recent_push(project1)).to eq(nil)
+ expect(subject.recent_push(project2)).to eq(push_event)
+
+ push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject)
+ push_event1 = create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject, data: push_data1)
+
+ expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest
+ end
end
describe '#authorized_groups' do
@@ -996,8 +1006,7 @@ describe User, models: true do
end
it 'does not include projects for which issues are disabled' do
- project = create(:project)
- project.update_attributes(issues_enabled: false)
+ project = create(:project, issues_access_level: ProjectFeature::DISABLED)
expect(user.projects_where_can_admin_issues.to_a).to be_empty
expect(user.can?(:admin_issue, project)).to eq(false)