diff options
Diffstat (limited to 'spec/models')
-rw-r--r-- | spec/models/ability_spec.rb | 13 | ||||
-rw-r--r-- | spec/models/build_spec.rb | 8 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 60 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 30 | ||||
-rw-r--r-- | spec/models/commit_range_spec.rb | 10 | ||||
-rw-r--r-- | spec/models/concerns/awardable_spec.rb | 10 | ||||
-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.rb | 25 | ||||
-rw-r--r-- | spec/models/members/project_member_spec.rb | 7 | ||||
-rw-r--r-- | spec/models/merge_request_diff_spec.rb | 21 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 141 | ||||
-rw-r--r-- | spec/models/network/graph_spec.rb | 12 | ||||
-rw-r--r-- | spec/models/note_spec.rb | 22 | ||||
-rw-r--r-- | spec/models/project_feature_spec.rb | 91 | ||||
-rw-r--r-- | spec/models/project_security_spec.rb | 112 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 85 | ||||
-rw-r--r-- | spec/models/repository_spec.rb | 48 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 13 |
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) |