diff options
Diffstat (limited to 'spec/models')
73 files changed, 900 insertions, 339 deletions
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 1bdf005c823..2f4a33a1868 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Ability, lib: true do describe '.can_edit_note?' do let(:project) { create(:empty_project) } - let!(:note) { create(:note_on_issue, project: project) } + let(:note) { create(:note_on_issue, project: project) } context 'using an anonymous user' do it 'returns false' do @@ -60,7 +60,7 @@ describe Ability, lib: true do describe '.users_that_can_read_project' do context 'using a public project' do it 'returns all the users' do - project = create(:project, :public) + project = create(:empty_project, :public) user = build(:user) expect(described_class.users_that_can_read_project([user], project)). @@ -69,7 +69,7 @@ describe Ability, lib: true do end context 'using an internal project' do - let(:project) { create(:project, :internal) } + let(:project) { create(:empty_project, :internal) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -120,7 +120,7 @@ describe Ability, lib: true do end context 'using a private project' do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -171,6 +171,33 @@ describe Ability, lib: true do end end + describe '.users_that_can_read_personal_snippet' do + def users_for_snippet(snippet) + described_class.users_that_can_read_personal_snippet(users, snippet) + end + + let(:users) { create_list(:user, 3) } + let(:author) { users[0] } + + it 'private snippet is readable only by its author' do + snippet = create(:personal_snippet, :private, author: author) + + expect(users_for_snippet(snippet)).to match_array([author]) + end + + it 'internal snippet is readable by all registered users' do + snippet = create(:personal_snippet, :public, author: author) + + expect(users_for_snippet(snippet)).to match_array(users) + end + + it 'public snippet is readable by all users' do + snippet = create(:personal_snippet, :public, author: author) + + expect(users_for_snippet(snippet)).to match_array(users) + end + end + describe '.issues_readable_by_user' do context 'with an admin user' do it 'returns all given issues' do @@ -220,7 +247,7 @@ describe Ability, lib: true do end describe '.project_disabled_features_rules' do - let(:project) { create(:project, wiki_access_level: ProjectFeature::DISABLED) } + let(:project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED) } subject { described_class.allowed(project.owner, project) } diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 3309a7fff9f..47cd5075a7d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::Build, :models do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:test_trace) { 'This is a test' } @@ -1401,4 +1401,14 @@ describe Ci::Build, :models do it { is_expected.to eq(%w[predefined project pipeline yaml secret]) } end end + + describe 'State transition: any => [:pending]' do + let(:build) { create(:ci_build, :created) } + + it 'queues BuildQueueWorker' do + expect(BuildQueueWorker).to receive(:perform_async).with(build.id) + + build.enqueue + end + end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index d1aee27057a..426be74cd02 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -122,55 +122,80 @@ describe Ci::Pipeline, models: true do end end - describe '#stages' do + describe 'pipeline stages' do before do - create(:commit_status, pipeline: pipeline, stage: 'build', name: 'linux', stage_idx: 0, status: 'success') - create(:commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'failed') - create(:commit_status, pipeline: pipeline, stage: 'deploy', name: 'staging', stage_idx: 2, status: 'running') - create(:commit_status, pipeline: pipeline, stage: 'test', name: 'rspec', stage_idx: 1, status: 'success') - end - - subject { pipeline.stages } - - context 'stages list' do - it 'returns ordered list of stages' do - expect(subject.map(&:name)).to eq(%w[build test deploy]) + create(:commit_status, pipeline: pipeline, + stage: 'build', + name: 'linux', + stage_idx: 0, + status: 'success') + + create(:commit_status, pipeline: pipeline, + stage: 'build', + name: 'mac', + stage_idx: 0, + status: 'failed') + + create(:commit_status, pipeline: pipeline, + stage: 'deploy', + name: 'staging', + stage_idx: 2, + status: 'running') + + create(:commit_status, pipeline: pipeline, + stage: 'test', + name: 'rspec', + stage_idx: 1, + status: 'success') + end + + describe '#stages' do + subject { pipeline.stages } + + context 'stages list' do + it 'returns ordered list of stages' do + expect(subject.map(&:name)).to eq(%w[build test deploy]) + end end - end - it 'returns a valid number of stages' do - expect(pipeline.stages_count).to eq(3) - end + context 'stages with statuses' do + let(:statuses) do + subject.map { |stage| [stage.name, stage.status] } + end - it 'returns a valid names of stages' do - expect(pipeline.stages_name).to eq(['build', 'test', 'deploy']) - end + it 'returns list of stages with correct statuses' do + expect(statuses).to eq([['build', 'failed'], + ['test', 'success'], + ['deploy', 'running']]) + end - context 'stages with statuses' do - let(:statuses) do - subject.map do |stage| - [stage.name, stage.status] + context 'when commit status is retried' do + before do + create(:commit_status, pipeline: pipeline, + stage: 'build', + name: 'mac', + stage_idx: 0, + status: 'success') + end + + it 'ignores the previous state' do + expect(statuses).to eq([['build', 'success'], + ['test', 'success'], + ['deploy', 'running']]) + end end end + end - it 'returns list of stages with statuses' do - expect(statuses).to eq([['build', 'failed'], - ['test', 'success'], - ['deploy', 'running'] - ]) + describe '#stages_count' do + it 'returns a valid number of stages' do + expect(pipeline.stages_count).to eq(3) end + end - context 'when build is retried' do - before do - create(:commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'success') - end - - it 'ignores the previous state' do - expect(statuses).to eq([['build', 'success'], - ['test', 'success'], - ['deploy', 'running'] - ]) - end + describe '#stages_name' do + it 'returns a valid names of stages' do + expect(pipeline.stages_name).to eq(['build', 'test', 'deploy']) end end end @@ -259,7 +284,7 @@ describe Ci::Pipeline, models: true do end describe 'merge request metrics' do - let(:project) { FactoryGirl.create :project } + let(:project) { create(:project, :repository) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) } @@ -314,7 +339,7 @@ describe Ci::Pipeline, models: true do end context 'with non-empty project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, @@ -865,7 +890,7 @@ describe Ci::Pipeline, models: true do end describe "#merge_requests" do - let(:project) { FactoryGirl.create :project } + let(:project) { create(:project, :repository) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do @@ -931,7 +956,7 @@ describe Ci::Pipeline, models: true do end describe 'notifications when pipeline success or failed' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index ef65eb99328..3f32248e52b 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -91,8 +91,7 @@ describe Ci::Runner, models: true do end describe '#can_pick?' do - let(:project) { create(:project) } - let(:pipeline) { create(:ci_pipeline, project: project) } + let(:pipeline) { create(:ci_pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:runner) { create(:ci_runner) } @@ -263,10 +262,66 @@ describe Ci::Runner, models: true do end end + describe '#tick_runner_queue' do + let(:runner) { create(:ci_runner) } + + it 'returns a new last_update value' do + expect(runner.tick_runner_queue).not_to be_empty + end + end + + describe '#ensure_runner_queue_value' do + let(:runner) { create(:ci_runner) } + + it 'sets a new last_update value when it is called the first time' do + last_update = runner.ensure_runner_queue_value + + expect_value_in_redis.to eq(last_update) + end + + it 'does not change if it is not expired and called again' do + last_update = runner.ensure_runner_queue_value + + expect(runner.ensure_runner_queue_value).to eq(last_update) + expect_value_in_redis.to eq(last_update) + end + + context 'updates runner queue after changing editable value' do + let!(:last_update) { runner.ensure_runner_queue_value } + + before do + runner.update(description: 'new runner') + end + + it 'sets a new last_update value' do + expect_value_in_redis.not_to eq(last_update) + end + end + + context 'does not update runner value after save' do + let!(:last_update) { runner.ensure_runner_queue_value } + + before do + runner.touch + end + + it 'has an old last_update value' do + expect_value_in_redis.to eq(last_update) + end + end + + def expect_value_in_redis + Gitlab::Redis.with do |redis| + runner_queue_key = runner.send(:runner_queue_key) + expect(redis.get(runner_queue_key)) + end + end + end + describe '.assignable_for' do let(:runner) { create(:ci_runner) } - let(:project) { create(:project) } - let(:another_project) { create(:project) } + let(:project) { create(:empty_project) } + let(:another_project) { create(:empty_project) } before do project.runners << runner diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 742bedb37e4..c4a9743a4e2 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -142,6 +142,78 @@ describe Ci::Stage, models: true do end end + describe '#success?' do + context 'when stage is successful' do + before do + create_job(:ci_build, status: :success) + create_job(:generic_commit_status, status: :success) + end + + it 'is successful' do + expect(stage).to be_success + end + end + + context 'when stage is not successful' do + before do + create_job(:ci_build, status: :failed) + create_job(:generic_commit_status, status: :success) + end + + it 'is not successful' do + expect(stage).not_to be_success + end + end + end + + describe '#has_warnings?' do + context 'when stage has warnings' do + context 'when using memoized warnings flag' do + context 'when there are warnings' do + let(:stage) { build(:ci_stage, warnings: true) } + + it 'has memoized warnings' do + expect(stage).not_to receive(:statuses) + expect(stage).to have_warnings + end + end + + context 'when there are no warnings' do + let(:stage) { build(:ci_stage, warnings: false) } + + it 'has memoized warnings' do + expect(stage).not_to receive(:statuses) + expect(stage).not_to have_warnings + end + end + end + + context 'when calculating warnings from statuses' do + before do + create(:ci_build, :failed, :allowed_to_fail, + stage: stage_name, pipeline: pipeline) + end + + it 'has warnings calculated from statuses' do + expect(stage).to receive(:statuses).and_call_original + expect(stage).to have_warnings + end + end + end + + context 'when stage does not have warnings' do + before do + create(:ci_build, :success, stage: stage_name, + pipeline: pipeline) + end + + it 'does not have warnings calculated from statuses' do + expect(stage).to receive(:statuses).and_call_original + expect(stage).not_to have_warnings + end + end + end + def create_job(type, status: 'success', stage: stage_name) create(type, pipeline: pipeline, stage: stage, status: status) end diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb index 30782ca75a0..e4bddf67096 100644 --- a/spec/models/commit_range_spec.rb +++ b/spec/models/commit_range_spec.rb @@ -7,7 +7,7 @@ describe CommitRange, models: true do it { is_expected.to include_module(Referable) } end - let!(:project) { create(:project, :public) } + let!(:project) { create(:project, :public, :repository) } let!(:commit1) { project.commit("HEAD~2") } let!(:commit2) { project.commit } diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 74b50d2908d..32f9366a14c 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit, models: true do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:commit) { project.commit } describe 'modules' do @@ -34,7 +34,7 @@ describe Commit, models: true do end describe '#to_reference' do - let(:project) { create(:project, path: 'sample-project') } + let(:project) { create(:project, :repository, path: 'sample-project') } let(:commit) { project.commit } it 'returns a String reference to the object' do @@ -42,13 +42,13 @@ describe Commit, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace) expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}" end end describe '#reference_link_text' do - let(:project) { create(:project, path: 'sample-project') } + let(:project) { create(:project, :repository, path: 'sample-project') } let(:commit) { project.commit } it 'returns a String reference to the object' do @@ -56,7 +56,7 @@ describe Commit, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace) expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}" end end @@ -131,7 +131,7 @@ eos describe '#closes_issues' do let(:issue) { create :issue, project: project } - let(:other_project) { create :project, :public } + let(:other_project) { create(:empty_project, :public) } let(:other_issue) { create :issue, project: other_project } let(:commiter) { create :user } @@ -154,7 +154,7 @@ eos end it_behaves_like 'a mentionable' do - subject { create(:project).commit } + subject { create(:project, :repository).commit } let(:author) { create(:user, email: subject.author_email) } let(:backref_text) { "commit #{subject.id}" } @@ -323,4 +323,50 @@ eos expect(new_commit.message).to eq(commit.message) end end + + describe '#work_in_progress?' do + ['squash! ', 'fixup! ', 'wip: ', 'WIP: ', '[WIP] '].each do |wip_prefix| + it "detects the '#{wip_prefix}' prefix" do + commit.message = "#{wip_prefix}#{commit.message}" + + expect(commit).to be_work_in_progress + end + end + + it "detects WIP for a commit just saying 'wip'" do + commit.message = "wip" + + expect(commit).to be_work_in_progress + end + + it "doesn't detect WIP for a commit that begins with 'FIXUP! '" do + commit.message = "FIXUP! #{commit.message}" + + expect(commit).not_to be_work_in_progress + end + + it "doesn't detect WIP for words starting with WIP" do + commit.message = "Wipout #{commit.message}" + + expect(commit).not_to be_work_in_progress + end + end + + describe '.valid_hash?' do + it 'checks hash contents' do + expect(described_class.valid_hash?('abcdef01239ABCDEF')).to be true + expect(described_class.valid_hash?("abcdef01239ABCD\nEF")).to be false + expect(described_class.valid_hash?(' abcdef01239ABCDEF ')).to be false + expect(described_class.valid_hash?('Gabcdef01239ABCDEF')).to be false + expect(described_class.valid_hash?('gabcdef01239ABCDEF')).to be false + expect(described_class.valid_hash?('-abcdef01239ABCDEF')).to be false + end + + it 'checks hash length' do + expect(described_class.valid_hash?('a' * 6)).to be false + expect(described_class.valid_hash?('a' * 7)).to be true + expect(described_class.valid_hash?('a' * 40)).to be true + expect(described_class.valid_hash?('a' * 41)).to be false + end + end end diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 64ea607eb95..bf4394f7d5b 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe CommitStatus, models: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, project: project, sha: project.commit.id) diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb index 49ab3c4b6e9..da003dbf794 100644 --- a/spec/models/compare_spec.rb +++ b/spec/models/compare_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Compare, models: true do include RepoHelpers - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:commit) { project.commit } let(:start_commit) { sample_image_commit } diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb index 4d0f51fe82a..dbfe3cd2d36 100644 --- a/spec/models/concerns/has_status_spec.rb +++ b/spec/models/concerns/has_status_spec.rb @@ -219,4 +219,10 @@ describe HasStatus do end end end + + describe '::DEFAULT_STATUS' do + it 'is a status created' do + expect(described_class::DEFAULT_STATUS).to eq 'created' + end + end end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index d7d31892e12..545a11912e3 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -301,7 +301,7 @@ describe Issue, "Issuable" do end describe '#labels_array' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:bug) { create(:label, project: project, title: 'bug') } let(:issue) { create(:issue, project: project) } @@ -315,7 +315,7 @@ describe Issue, "Issuable" do end describe '#user_notes_count' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } @@ -359,7 +359,7 @@ describe Issue, "Issuable" do end describe ".with_label" do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:bug) { create(:label, project: project, title: 'bug') } let(:feature) { create(:label, project: project, title: 'feature') } let(:enhancement) { create(:label, project: project, title: 'enhancement') } diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index 132858950d5..2092576e981 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -13,7 +13,7 @@ describe Mentionable do end describe 'references' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:mentionable) { Example.new } it 'excludes JIRA references' do @@ -30,12 +30,20 @@ describe Issue, "Mentionable" do describe '#mentioned_users' do let!(:user) { create(:user, username: 'stranger') } let!(:user2) { create(:user, username: 'john') } - let!(:issue) { create(:issue, description: "#{user.to_reference} mentioned") } + let!(:user3) { create(:user, username: 'jim') } + let(:issue) { create(:issue, description: "#{user.to_reference} mentioned") } subject { issue.mentioned_users } - it { is_expected.to include(user) } - it { is_expected.not_to include(user2) } + it { expect(subject).to contain_exactly(user) } + + context 'when a note on personal snippet' do + let!(:note) { create(:note_on_personal_snippet, note: "#{user.to_reference} mentioned #{user3.to_reference}") } + + subject { note.mentioned_users } + + it { expect(subject).to contain_exactly(user, user3) } + end end describe '#referenced_mentionables' do @@ -75,13 +83,13 @@ describe Issue, "Mentionable" do end describe '#create_cross_references!' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:author) { build(:user) } let(:commit) { project.commit } let(:commit2) { project.commit } let!(:issue) do - create(:issue, project: project, description: commit.to_reference) + create(:issue, project: project, description: "See #{commit.to_reference}") end it 'correctly removes already-mentioned Commits' do @@ -92,7 +100,7 @@ describe Issue, "Mentionable" do end describe '#create_new_cross_references!' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:author) { create(:author) } let(:issues) { create_list(:issue, 2, project: project, author: author) } @@ -138,6 +146,16 @@ describe Issue, "Mentionable" do issue.update_attributes(description: issues[1].to_reference) issue.create_new_cross_references! end + + it 'notifies new references from project snippet note' do + snippet = create(:snippet, project: project) + note = create(:note, note: issues[0].to_reference, noteable: snippet, project: project, author: author) + + expect(SystemNoteService).to receive(:cross_reference).with(issues[1], any_args) + + note.update_attributes(note: issues[1].to_reference) + note.create_new_cross_references! + end end def create_issue(description:) diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 0e097559b59..ad703a6c8bb 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do let(:member) { create(:user) } let(:guest) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:milestone) { create(:milestone, project: project) } let!(:issue) { create(:issue, project: project, milestone: milestone) } let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) } diff --git a/spec/models/concerns/presentable_spec.rb b/spec/models/concerns/presentable_spec.rb new file mode 100644 index 00000000000..941647a79fb --- /dev/null +++ b/spec/models/concerns/presentable_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Presentable do + let(:build) { Ci::Build.new } + + describe '#present' do + it 'returns a presenter' do + expect(build.present).to be_a(Ci::BuildPresenter) + end + + it 'takes optional attributes' do + expect(build.present(foo: 'bar').foo).to eq('bar') + end + end +end diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 9041690023f..6cf5877424d 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeaturesCompatibility do - let(:project) { create(:project) } + let(:project) { create(:empty_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 diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index b556135532f..30443534cca 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -68,4 +68,14 @@ describe Group, 'Routable' do end end end + + describe '.member_descendants' do + let!(:user) { create(:user) } + let!(:nested_group) { create(:group, parent: group) } + + before { group.add_owner(user) } + subject { described_class.member_descendants(user.id) } + + it { is_expected.to eq([nested_group]) } + end end diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb index 70f985afefb..3b7cc7d9e2e 100644 --- a/spec/models/cycle_analytics/code_spec.rb +++ b/spec/models/cycle_analytics/code_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#code', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb index e4b6a8f4518..5c73edbbc53 100644 --- a/spec/models/cycle_analytics/issue_spec.rb +++ b/spec/models/cycle_analytics/issue_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#issue', models: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb index dc5b04852d6..55483fc876a 100644 --- a/spec/models/cycle_analytics/plan_spec.rb +++ b/spec/models/cycle_analytics/plan_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#plan', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index 5e99188f318..591bbdddf55 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#production', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb index 45baa5f7006..33d2c0a7416 100644 --- a/spec/models/cycle_analytics/review_spec.rb +++ b/spec/models/cycle_analytics/review_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#review', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index 77625aad580..00693d67475 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -3,9 +3,10 @@ require 'spec_helper' describe 'CycleAnalytics#staging', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } + subject { CycleAnalytics.new(project, from: from_date) } generate_cycle_analytics_spec( diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb index 27a117d2d76..f857ea6cbec 100644 --- a/spec/models/cycle_analytics/test_spec.rb +++ b/spec/models/cycle_analytics/test_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#test', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb index 8a1e337c1a3..aacc178a19e 100644 --- a/spec/models/deploy_keys_project_spec.rb +++ b/spec/models/deploy_keys_project_spec.rb @@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do end describe "Destroying" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:deploy_keys_project, project: project) } let(:deploy_key) { subject.deploy_key } @@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do end context "when the deploy key is used by more than one project" do - let!(:other_project) { create(:project) } + let!(:other_project) { create(:empty_project) } before do other_project.deploy_keys << deploy_key diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index ca594a320c0..fc4435a2f64 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -17,7 +17,7 @@ describe Deployment, models: true do it { is_expected.to validate_presence_of(:sha) } describe '#includes_commit?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } let(:deployment) do create(:deployment, environment: environment, sha: project.commit.id) diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 3db5937a4f3..9ea3a4b7020 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe DiffNote, models: true do include RepoHelpers - let(:project) { create(:project) } - let(:merge_request) { create(:merge_request, source_project: project) } + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } let(:commit) { project.commit(sample_commit.id) } let(:path) { "files/ruby/popen.rb" } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 96efe1696c3..b2e06541e66 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -32,7 +32,7 @@ describe Environment, models: true do end describe '#includes_commit?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } context 'without a last deployment' do it "returns false" do @@ -81,7 +81,7 @@ describe Environment, models: true do end describe '#first_deployment_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let(:head_commit) { project.commit } diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index f8660da031d..349474bb656 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -27,7 +27,7 @@ describe Event, models: true do end describe "Push event" do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } let(:user) { project.owner } let(:event) { create_event(project, user) } @@ -187,7 +187,7 @@ describe Event, models: true do end context 'merge request diff note event' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) } let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) } let(:target) { note_on_merge_request } @@ -202,7 +202,7 @@ describe Event, models: true do end context 'private project' do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } it do expect(event.visible_to_user?(non_member)).to eq false diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 1863581f57b..454550c9710 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ForkedProjectLink, "add link on fork" do - let(:project_from) { create(:project) } + let(:project_from) { create(:project, :repository) } let(:namespace) { create(:namespace) } let(:user) { create(:user, namespace: namespace) } @@ -21,7 +21,7 @@ end describe '#forked?' do let(:forked_project_link) { build(:forked_project_link) } - let(:project_from) { create(:project) } + let(:project_from) { create(:project, :repository) } let(:project_to) { create(:project, forked_project_link: forked_project_link) } before :each do diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index 6004bfdb7b7..f4c3e6d503f 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -1,10 +1,20 @@ require 'spec_helper' describe GenericCommitStatus, models: true do - let(:pipeline) { create(:ci_pipeline) } + let(:project) { create(:empty_project) } + let(:pipeline) { create(:ci_pipeline, project: project) } + let(:external_url) { 'http://example.gitlab.com/status' } let(:generic_commit_status) do - create(:generic_commit_status, pipeline: pipeline) + create(:generic_commit_status, pipeline: pipeline, + target_url: external_url) + end + + describe 'validations' do + it { is_expected.to validate_length_of(:target_url).is_at_most(255) } + it { is_expected.to allow_value(nil).for(:target_url) } + it { is_expected.to allow_value('http://gitlab.com/s').for(:target_url) } + it { is_expected.not_to allow_value('javascript:alert(1)').for(:target_url) } end describe '#context' do @@ -22,10 +32,25 @@ describe GenericCommitStatus, models: true do describe '#detailed_status' do let(:user) { create(:user) } + let(:status) { generic_commit_status.detailed_status(user) } it 'returns detailed status object' do - expect(generic_commit_status.detailed_status(user)) - .to be_a Gitlab::Ci::Status::Success + expect(status).to be_a Gitlab::Ci::Status::Success + end + + context 'when user has ability to see datails' do + before { project.team << [user, :developer] } + + it 'details path points to an external URL' do + expect(status).to have_details + expect(status.details_path).to eq external_url + end + end + + context 'when user should not see details' do + it 'does not have details' do + expect(status).not_to have_details + end end end diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index d87684fd49e..cacbab8bcb1 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do let(:user) { create(:user) } let(:user2) { create(:user) } let(:group) { create(:group) } - let(:project1) { create(:project, group: group) } - let(:project2) { create(:project, path: 'gitlab-ci', group: group) } - let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } + let(:project1) { create(:empty_project, group: group) } + let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) } + let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) } describe '.build_collection' do let(:milestone1_due_date) { 2.weeks.from_now.to_date } diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index 601167c3bd3..916afb7aaf5 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GroupMilestone, models: true do let(:group) { create(:group) } - let(:project) { create(:project, group: group) } + let(:project) { create(:empty_project, group: group) } let(:project_milestone) do create(:milestone, title: "Milestone v1.2", project: project) end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 45fe927202b..9ca50555191 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -81,13 +81,19 @@ describe Group, models: true do describe 'public_only' do subject { described_class.public_only.to_a } - it{ is_expected.to eq([group]) } + it { is_expected.to eq([group]) } end describe 'public_and_internal_only' do subject { described_class.public_and_internal_only.to_a } - it{ is_expected.to match_array([group, internal_group]) } + it { is_expected.to match_array([group, internal_group]) } + end + + describe 'non_public_only' do + subject { described_class.non_public_only.to_a } + + it { is_expected.to match_array([private_group, internal_group]) } end end @@ -269,6 +275,12 @@ describe Group, models: true do it 'returns the canonical URL' do expect(group.web_url).to include("groups/#{group.name}") end + + context 'nested group' do + let(:nested_group) { create(:group, :nested) } + + it { expect(nested_group.web_url).to include("groups/#{nested_group.full_path}") } + end end describe 'nested group' do diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index d79f929f7a1..582b54c0712 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Guest, lib: true do - let(:public_project) { create(:project, :public) } - let(:private_project) { create(:project, :private) } - let(:internal_project) { create(:project, :internal) } + let(:public_project) { build_stubbed(:empty_project, :public) } + let(:private_project) { build_stubbed(:empty_project, :private) } + let(:internal_project) { build_stubbed(:empty_project, :internal) } describe '.can_pull?' do context 'when project is private' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index ad2b710041a..e8caad00c44 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -4,7 +4,7 @@ describe SystemHook, models: true do describe "execute" do let(:system_hook) { create(:system_hook) } let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:empty_project, namespace: user.namespace) } let(:group) { create(:group) } before do diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index e52b9d75cef..9d4db1bfb52 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -25,7 +25,7 @@ describe WebHook, models: true do end describe "execute" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:project_hook) { create(:project_hook) } before(:each) do diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb index 2459a49f095..08712f2a768 100644 --- a/spec/models/issue/metrics_spec.rb +++ b/spec/models/issue/metrics_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Issue::Metrics, models: true do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:issue, project: project) } diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index d742c814680..d8aed25c041 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe IssueCollection do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } let(:collection) { described_class.new([issue1, issue2]) } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index bfa36d92ac3..40c0a75c364 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -35,7 +35,7 @@ describe Issue, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(issue.to_reference(another_project)).to eq "sample-project#1" end end @@ -60,9 +60,9 @@ describe Issue, models: true do end describe '#closed_by_merge_requests' do - let(:project) { create(:project) } - let(:issue) { create(:issue, project: project, state: "opened")} - let(:closed_issue) { build(:issue, project: project, state: "closed")} + let(:project) { create(:project, :repository) } + let(:issue) { create(:issue, project: project)} + let(:closed_issue) { build(:issue, :closed, project: project)} let(:mr) do opts = { @@ -104,7 +104,7 @@ describe Issue, models: true do describe '#referenced_merge_requests' do it 'returns the referenced merge requests' do - project = create(:project, :public) + project = create(:empty_project, :public) mr1 = create(:merge_request, source_project: project, @@ -137,7 +137,7 @@ describe Issue, models: true do end context 'user is reporter in project issue belongs to' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } before { project.team << [user, :reporter] } @@ -151,7 +151,7 @@ describe Issue, models: true do context 'checking destination project also' do subject { issue.can_move?(user, to_project) } - let(:to_project) { create(:project) } + let(:to_project) { create(:empty_project) } context 'destination project allowed' do before { to_project.team << [user, :reporter] } @@ -217,7 +217,7 @@ describe Issue, models: true do end it_behaves_like 'an editable mentionable' do - subject { create(:issue) } + subject { create(:issue, project: create(:project, :repository)) } let(:backref_text) { "issue #{subject.to_reference}" } let(:set_mentionable_text) { ->(txt){ subject.description = txt } } @@ -246,7 +246,7 @@ describe Issue, models: true do describe '#participants' do context 'using a public project' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project) } let!(:note1) do @@ -268,7 +268,7 @@ describe Issue, models: true do context 'using a private project' do it 'does not include mentioned users that do not have access to the project' do - project = create(:project) + project = create(:empty_project) user = create(:user) issue = create(:issue, project: project) diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 5eaddd822be..7c40cfd8253 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -30,11 +30,30 @@ describe Key, models: true do end describe "#update_last_used_at" do - it "enqueues a UseKeyWorker job" do - key = create(:key) + let(:key) { create(:key) } + + context 'when key was not updated during the last day' do + before do + allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return('000000') + end + + it 'enqueues a UseKeyWorker job' do + expect(UseKeyWorker).to receive(:perform_async).with(key.id) + key.update_last_used_at + end + end + + context 'when key was updated during the last day' do + before do + allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return(false) + end - expect(UseKeyWorker).to receive(:perform_async).with(key.id) - key.update_last_used_at + it 'does not enqueue a UseKeyWorker job' do + expect(UseKeyWorker).not_to receive(:perform_async) + key.update_last_used_at + end end end end diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 4f7c8a36cb5..16e2144d6a1 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -481,7 +481,7 @@ describe Member, models: true do describe "destroying a record", truncate: true do it "refreshes user's authorized projects" do - project = create(:project, :private) + project = create(:empty_project, :private) user = create(:user) member = project.team << [user, :reporter] diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 68f72f5c86e..90d14c2c0b9 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -83,8 +83,8 @@ describe ProjectMember, models: true do describe '.import_team' do before do - @project_1 = create :project - @project_2 = create :project + @project_1 = create(:empty_project) + @project_2 = create(:empty_project) @user_1 = create :user @user_2 = create :user @@ -131,8 +131,8 @@ describe ProjectMember, models: true do describe '.truncate_teams' do before do - @project_1 = create :project - @project_2 = create :project + @project_1 = create(:empty_project) + @project_2 = create(:empty_project) @user_1 = create :user @user_2 = create :user diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb index 255db41cb19..9afed311e27 100644 --- a/spec/models/merge_request/metrics_spec.rb +++ b/spec/models/merge_request/metrics_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' describe MergeRequest::Metrics, models: true do - let(:project) { create(:project) } - - subject { create(:merge_request, source_project: project) } + subject { create(:merge_request) } describe "when recording the default set of metrics on merge request save" do it "records the merge time" do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 861426acbc3..32ed1e96749 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -65,7 +65,7 @@ describe MergeRequest, models: true do end describe '#target_branch_sha' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } subject { create(:merge_request, source_project: project, target_project: project) } @@ -150,7 +150,7 @@ describe MergeRequest, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(merge_request.to_reference(another_project)).to eq "sample-project!1" end @@ -245,8 +245,8 @@ describe MergeRequest, models: true do describe '#for_fork?' do it 'returns true if the merge request is for a fork' do - subject.source_project = create(:project, namespace: create(:group)) - subject.target_project = create(:project, namespace: create(:group)) + subject.source_project = build_stubbed(:empty_project, namespace: create(:group)) + subject.target_project = build_stubbed(:empty_project, namespace: create(:group)) expect(subject.for_fork?).to be_truthy end @@ -501,8 +501,8 @@ describe MergeRequest, models: true do end describe '#diverged_commits_count' do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } context 'when the target branch does not exist anymore' do subject { create(:merge_request, source_project: project, target_project: project) } @@ -727,7 +727,7 @@ describe MergeRequest, models: true do end describe '#participants' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:mr) do create(:merge_request, source_project: project, target_project: project) @@ -768,15 +768,17 @@ describe MergeRequest, models: true do end describe '#check_if_can_be_merged' do - let(:project) { create(:project, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) } subject { create(:merge_request, source_project: project, merge_status: :unchecked) } context 'when it is not broken and has no conflicts' do - it 'is marked as mergeable' do + before do allow(subject).to receive(:broken?) { false } allow(project.repository).to receive(:can_be_merged?).and_return(true) + end + it 'is marked as mergeable' do expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged') end end @@ -787,6 +789,12 @@ describe MergeRequest, models: true do it 'becomes unmergeable' do expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') end + + it 'creates Todo on unmergeability' do + expect_any_instance_of(TodoService).to receive(:merge_request_became_unmergeable).with(subject) + + subject.check_if_can_be_merged + end end context 'when it has conflicts' do @@ -802,7 +810,7 @@ describe MergeRequest, models: true do end describe '#mergeable?' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:merge_request, source_project: project) } @@ -822,7 +830,7 @@ describe MergeRequest, models: true do end describe '#mergeable_state?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } subject { create(:merge_request, source_project: project) } @@ -949,7 +957,7 @@ describe MergeRequest, models: true do let(:merge_request) { create(:merge_request_with_diff_notes, source_project: project) } context 'when project.only_allow_merge_if_all_discussions_are_resolved == true' do - let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) } + let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) } context 'with all discussions resolved' do before do @@ -983,7 +991,7 @@ describe MergeRequest, models: true do end context 'when project.only_allow_merge_if_all_discussions_are_resolved == false' do - let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: false) } + let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: false) } context 'with unresolved discussions' do before do @@ -998,7 +1006,7 @@ describe MergeRequest, models: true do end describe "#environments" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } context 'with multiple environments' do @@ -1016,7 +1024,7 @@ describe MergeRequest, models: true do context 'with environments on source project' do let(:source_project) do - create(:project) do |fork_project| + create(:project, :repository) do |fork_project| fork_project.create_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) end end @@ -1393,8 +1401,8 @@ describe MergeRequest, models: true do end describe "#source_project_missing?" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project) } + let(:fork_project) { create(:empty_project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1431,8 +1439,8 @@ describe MergeRequest, models: true do end describe "#closed_without_fork?" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project) } + let(:fork_project) { create(:empty_project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1477,9 +1485,9 @@ describe MergeRequest, models: true do end context 'forked project' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:user) { create(:user) } - let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) } + let(:fork_project) { create(:empty_project, forked_from_project: project, namespace: user.namespace) } let!(:merge_request) do create(:closed_merge_request, @@ -1523,7 +1531,7 @@ describe MergeRequest, models: true do status: status) end - let(:project) { create(:project, :public, only_allow_merge_if_build_succeeds: true) } + let(:project) { create(:project, :public, :repository, only_allow_merge_if_build_succeeds: true) } let(:developer) { create(:user) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 064f29d2d66..3cee2b7714f 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -24,7 +24,7 @@ describe Milestone, models: true do it { is_expected.to have_many(:issues) } end - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:milestone) { create(:milestone, project: project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } @@ -44,7 +44,7 @@ describe Milestone, models: true do end it "accepts the same title in another project" do - project = build(:project) + project = build(:empty_project) new_milestone = Milestone.new(project: project, title: milestone.title) expect(new_milestone).to be_valid @@ -257,7 +257,7 @@ describe Milestone, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(milestone.to_reference(another_project)).to eq "sample-project%1" end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 600538ff5f4..4e96f19eb6f 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -5,6 +5,8 @@ describe Namespace, models: true do it { is_expected.to have_many :projects } it { is_expected.to have_many :project_statistics } + it { is_expected.to belong_to :parent } + it { is_expected.to have_many :children } it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) } @@ -105,7 +107,7 @@ describe Namespace, models: true do describe '#move_dir' do before do @namespace = create :namespace - @project = create :project, namespace: @namespace + @project = create(:empty_project, namespace: @namespace) allow(@namespace).to receive(:path_changed?).and_return(true) end @@ -117,6 +119,7 @@ describe Namespace, models: true do new_path = @namespace.path + "_new" allow(@namespace).to receive(:path_was).and_return(@namespace.path) allow(@namespace).to receive(:path).and_return(new_path) + expect(@namespace).to receive(:remove_exports!) expect(@namespace.move_dir).to be_truthy end @@ -136,14 +139,20 @@ describe Namespace, models: true do end describe :rm_dir do - let!(:project) { create(:project, namespace: namespace) } + let!(:project) { create(:empty_project, namespace: namespace) } let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } - before { namespace.destroy } - it "removes its dirs when deleted" do + namespace.destroy + expect(File.exist?(path)).to be(false) end + + it 'removes the exports folder' do + expect(namespace).to receive(:remove_exports!) + + namespace.destroy + end end describe '.find_by_path_or_name' do @@ -182,17 +191,31 @@ describe Namespace, models: true do it { expect(nested_group.full_name).to eq("#{group.name} / #{nested_group.name}") } end - describe '#parents' do + describe '#ancestors' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:deep_nested_group) { create(:group, parent: nested_group) } let(:very_deep_nested_group) { create(:group, parent: deep_nested_group) } - it 'returns the correct parents' do - expect(very_deep_nested_group.parents).to eq([group, nested_group, deep_nested_group]) - expect(deep_nested_group.parents).to eq([group, nested_group]) - expect(nested_group.parents).to eq([group]) - expect(group.parents).to eq([]) + it 'returns the correct ancestors' do + expect(very_deep_nested_group.ancestors).to eq([group, nested_group, deep_nested_group]) + expect(deep_nested_group.ancestors).to eq([group, nested_group]) + expect(nested_group.ancestors).to eq([group]) + expect(group.ancestors).to eq([]) + end + end + + describe '#descendants' do + let!(:group) { create(:group) } + let!(:nested_group) { create(:group, parent: group) } + let!(:deep_nested_group) { create(:group, parent: nested_group) } + let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) } + + it 'returns the correct descendants' do + expect(very_deep_nested_group.descendants.to_a).to eq([]) + expect(deep_nested_group.descendants.to_a).to eq([very_deep_nested_group]) + expect(nested_group.descendants.to_a).to eq([deep_nested_group, very_deep_nested_group]) + expect(group.descendants.to_a).to eq([nested_group, deep_nested_group, very_deep_nested_group]) end end end diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb index b76513d2a3c..492c4e01bd8 100644 --- a/spec/models/network/graph_spec.rb +++ b/spec/models/network/graph_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Network::Graph, models: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:note_on_commit) { create(:note_on_commit, project: project) } it '#initialize' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 310fecd8a5c..1cde9e04951 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -42,7 +42,7 @@ describe Note, models: true do context 'when noteable and note project differ' do subject do build(:note, noteable: build_stubbed(:issue), - project: build_stubbed(:project)) + project: build_stubbed(:empty_project)) end it { is_expected.to be_invalid } @@ -52,6 +52,19 @@ describe Note, models: true do subject { create(:note) } it { is_expected.to be_valid } end + + context 'when project is missing for a project related note' do + subject { build(:note, project: nil, noteable: build_stubbed(:issue)) } + it { is_expected.to be_invalid } + end + + context 'when noteable is a personal snippet' do + subject { build(:note_on_personal_snippet) } + + it 'is valid without project' do + is_expected.to be_valid + end + end end describe "Commit notes" do @@ -80,8 +93,8 @@ describe Note, models: true do describe 'authorization' do before do - @p1 = create(:project) - @p2 = create(:project) + @p1 = create(:empty_project) + @p2 = create(:empty_project) @u1 = create(:user) @u2 = create(:user) @u3 = create(:user) @@ -125,7 +138,7 @@ describe Note, models: true do it_behaves_like 'an editable mentionable' do subject { create :note, noteable: issue, project: issue.project } - let(:issue) { create :issue } + let(:issue) { create(:issue, project: create(:project, :repository)) } let(:backref_text) { issue.gfm_reference } let(:set_mentionable_text) { ->(txt) { subject.note = txt } } end @@ -139,6 +152,7 @@ describe Note, models: true do with([{ text: note1.note, context: { + skip_project_check: false, pipeline: :note, cache_key: [note1, "note"], project: note1.project, @@ -150,6 +164,7 @@ describe Note, models: true do with([{ text: note2.note, context: { + skip_project_check: false, pipeline: :note, cache_key: [note2, "note"], project: note2.project, @@ -176,10 +191,10 @@ describe Note, models: true do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:project, namespace: private_user.namespace).tap { |p| p.team << [private_user, :master] } } + let(:private_project) { create(:empty_project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } let(:private_issue) { create(:issue, project: private_project) } - let(:ext_proj) { create(:project, :public) } + let(:ext_proj) { create(:empty_project, :public) } let(:ext_issue) { create(:issue, project: ext_proj) } let(:note) do @@ -222,7 +237,7 @@ describe Note, models: true do describe '#participants' do it 'includes the note author' do - project = create(:project, :public) + project = create(:empty_project, :public) issue = create(:issue, project: project) note = create(:note_on_issue, noteable: issue, project: project) @@ -306,4 +321,70 @@ describe Note, models: true do end end end + + describe '#for_personal_snippet?' do + it 'returns false for a project snippet note' do + expect(build(:note_on_project_snippet).for_personal_snippet?).to be_falsy + end + + it 'returns true for a personal snippet note' do + expect(build(:note_on_personal_snippet).for_personal_snippet?).to be_truthy + end + end + + describe '#to_ability_name' do + it 'returns snippet for a project snippet note' do + expect(build(:note_on_project_snippet).to_ability_name).to eq('snippet') + end + + it 'returns personal_snippet for a personal snippet note' do + expect(build(:note_on_personal_snippet).to_ability_name).to eq('personal_snippet') + end + + it 'returns merge_request for an MR note' do + expect(build(:note_on_merge_request).to_ability_name).to eq('merge_request') + end + + it 'returns issue for an issue note' do + expect(build(:note_on_issue).to_ability_name).to eq('issue') + end + + it 'returns issue for a commit note' do + expect(build(:note_on_commit).to_ability_name).to eq('commit') + end + end + + describe '#cache_markdown_field' do + let(:html) { '<p>some html</p>'} + + context 'note for a project snippet' do + let(:note) { build(:note_on_project_snippet) } + + before do + expect(Banzai::Renderer).to receive(:cacheless_render_field). + with(note, :note, { skip_project_check: false }).and_return(html) + + note.save + end + + it 'creates a note' do + expect(note.note_html).to eq(html) + end + end + + context 'note for a personal snippet' do + let(:note) { build(:note_on_personal_snippet) } + + before do + expect(Banzai::Renderer).to receive(:cacheless_render_field). + with(note, :note, { skip_project_check: true }).and_return(html) + + note.save + end + + it 'creates a note' do + expect(note.note_html).to eq(html) + end + end + end end diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index a55d43ab2f9..8589f1eb712 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeature do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:user) { create(:user) } describe '#feature_available?' do @@ -35,7 +35,7 @@ describe ProjectFeature do it "returns true when user is a member of project group" do group = create(:group) - project = create(:project, namespace: group) + project = create(:empty_project, namespace: group) group.add_developer(user) features.each do |feature| diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 47397a822c1..59a4ae1b799 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -17,7 +17,7 @@ describe ProjectGroupLink do describe "destroying a record", truncate: true do it "refreshes group users' authorized projects" do - project = create(:project, :private) + project = create(:empty_project, :private) group = create(:group) reporter = create(:user) group_users = group.users diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb index 4d538cac007..9cdbfa44e5b 100644 --- a/spec/models/project_label_spec.rb +++ b/spec/models/project_label_spec.rb @@ -100,7 +100,7 @@ describe ProjectLabel, models: true do end context 'cross project reference' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'using name' do it 'returns cross reference with label name' do diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 8e5145e824b..48aef3a93f2 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -18,7 +18,7 @@ describe AsanaService, models: true do describe 'Execute' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } def create_data_for_commits(*messages) { diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index 4c5acb7990b..96f00af898e 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -8,7 +8,7 @@ describe AssemblaService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @assembla_service = AssemblaService.new diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index a3b9d084a75..953e664fb66 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -22,7 +22,7 @@ describe CampfireService, models: true do describe "#execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @campfire_service = CampfireService.new diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 42c2ed668bc..f9307d6de7b 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -27,7 +27,7 @@ describe DroneCiService, models: true, caching: true do shared_context :drone_ci_service do let(:drone) { DroneCiService.new } - let(:project) { create(:project, name: 'project') } + let(:project) { create(:project, :repository, name: 'project') } let(:path) { "#{project.namespace.path}/#{project.path}" } let(:drone_url) { 'http://drone.example.com' } let(:sha) { '2ab7834c' } diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index 342d86aeca9..bdeea1db1e3 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -23,7 +23,7 @@ describe ExternalWikiService, models: true do end describe 'External wiki' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when it is active' do before do diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index d6db02d6e76..a97e8c6e4ce 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -22,7 +22,7 @@ describe FlowdockService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @flowdock_service = FlowdockService.new diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index 529044d1d8b..a13fbae03eb 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -24,7 +24,7 @@ describe GemnasiumService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @gemnasium_service = GemnasiumService.new diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index 9b80f0e7296..dcb70ee28a8 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -8,21 +8,21 @@ describe GitlabIssueTrackerService, models: true do describe 'Validations' do context 'when service is active' do - subject { described_class.new(project: create(:project), active: true) } + subject { described_class.new(project: create(:empty_project), active: true) } it { is_expected.to validate_presence_of(:issues_url) } it_behaves_like 'issue tracker service URL attribute', :issues_url end context 'when service is inactive' do - subject { described_class.new(project: create(:project), active: false) } + subject { described_class.new(project: create(:empty_project), active: false) } it { is_expected.not_to validate_presence_of(:issues_url) } end end describe 'project and issue urls' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'with absolute urls' do before do diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 2da3a9cb09f..bf422ac7ce1 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -22,8 +22,8 @@ describe HipchatService, models: true do describe "Execute" do let(:hipchat) { HipchatService.new } - let(:user) { create(:user, username: 'username') } - let(:project) { create(:project, name: 'project') } + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' } let(:project_name) { project.name_with_namespace.gsub(/\s/, '') } let(:token) { 'verySecret' } @@ -165,7 +165,7 @@ describe HipchatService, models: true do context "Note events" do let(:user) { create(:user) } - let(:project) { create(:project, creator_id: user.id) } + let(:project) { create(:project, :repository, creator: user) } context 'when commit comment event triggered' do let(:commit_note) do diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index f8c45b37561..b9fb6f3f6f4 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -25,7 +25,7 @@ describe IrkerService, models: true do describe 'Execute' do let(:irker) { IrkerService.new } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:sample_data) do Gitlab::DataBuilder::Push.build_sample(project, user) end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 862e3a72a73..2f6b159d76e 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -71,7 +71,7 @@ describe JiraService, models: true do describe '#close_issue' do let(:custom_base_url) { 'http://custom_url' } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:merge_request) { create(:merge_request) } before do @@ -207,12 +207,12 @@ describe JiraService, models: true do end describe "Stored password invalidation" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context "when a password was previously set" do before do @jira_service = JiraService.create!( - project: create(:project), + project: project, properties: { url: 'http://jira.example.com/rest/api/2', username: 'mic', @@ -252,7 +252,7 @@ describe JiraService, models: true do context "when no password was previously set" do before do @jira_service = JiraService.create( - project: create(:project), + project: project, properties: { url: 'http://jira.example.com/rest/api/2', username: 'mic' @@ -281,7 +281,7 @@ describe JiraService, models: true do end describe 'description and title' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when it is not set' do before do @@ -316,7 +316,7 @@ describe JiraService, models: true do end describe 'project and issue urls' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when gitlab.yml was initialized' do before do diff --git a/spec/models/project_services/pipeline_email_service_spec.rb b/spec/models/project_services/pipeline_email_service_spec.rb index 7c8824485f5..03932895b0e 100644 --- a/spec/models/project_services/pipeline_email_service_spec.rb +++ b/spec/models/project_services/pipeline_email_service_spec.rb @@ -7,7 +7,7 @@ describe PipelinesEmailService do create(:ci_pipeline, project: project, sha: project.commit('master').sha) end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:recipient) { 'test@gitlab.com' } let(:data) do diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 8fc92a9ab51..a7e7594a7d5 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -27,7 +27,7 @@ describe PushoverService, models: true do describe 'Execute' do let(:pushover) { PushoverService.new } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:sample_data) do Gitlab::DataBuilder::Push.build_sample(project, user) end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e93a4e62244..646a1311462 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -73,9 +73,7 @@ describe Project, models: true do context 'after initialized' do it "has a project_feature" do - project = FactoryGirl.build(:project) - - expect(project.project_feature.present?).to be_present + expect(Project.new.project_feature).to be_present end end @@ -129,7 +127,7 @@ describe Project, models: true do end describe 'validation' do - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) } @@ -148,7 +146,7 @@ describe Project, models: true do it { is_expected.to validate_presence_of(:repository_storage) } it 'does not allow new projects beyond user limits' do - project2 = build(:project) + project2 = build(:empty_project) 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/) @@ -157,7 +155,7 @@ describe Project, models: true do describe 'wiki path conflict' do context "when the new path has been used by the wiki of other Project" do it 'has an error on the name attribute' do - new_project = build_stubbed(:project, namespace_id: project.namespace_id, path: "#{project.path}.wiki") + new_project = build_stubbed(:empty_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') @@ -166,8 +164,8 @@ describe Project, models: true do context "when the new wiki path has been used by the path of other Project" do it 'has 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') + project_with_wiki_suffix = create(:empty_project, path: 'foo.wiki') + new_project = build_stubbed(:empty_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') @@ -176,7 +174,7 @@ describe Project, models: true do end context 'repository storages inclussion' do - let(:project2) { build(:project, repository_storage: 'missing') } + let(:project2) { build(:empty_project, repository_storage: 'missing') } before do storages = { 'custom' => 'tmp/tests/custom_repositories' } @@ -352,7 +350,7 @@ describe Project, models: true do end describe '#repository_storage_path' do - let(:project) { create(:project, repository_storage: 'custom') } + let(:project) { create(:empty_project, repository_storage: 'custom') } before do FileUtils.mkdir('tmp/tests/custom_repositories') @@ -412,7 +410,7 @@ describe Project, models: true do describe 'last_activity methods' do let(:timestamp) { 2.hours.ago } # last_activity_at gets set to created_at upon creation - let(:project) { create(:project, created_at: timestamp, updated_at: timestamp) } + let(:project) { create(:empty_project, created_at: timestamp, updated_at: timestamp) } describe 'last_activity' do it 'alias last_activity to last_event' do @@ -496,7 +494,7 @@ describe Project, models: true do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlabhq', namespace: @group) + @project = create(:empty_project, name: 'gitlabhq', namespace: @group) end it { expect(@project.to_param).to eq('gitlabhq') } @@ -522,7 +520,7 @@ describe Project, models: true do end describe '#repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'returns valid repo' do expect(project.repository).to be_kind_of(Repository) @@ -530,20 +528,22 @@ describe Project, models: true do end describe '#default_issues_tracker?' do - let(:project) { create(:project) } - let(:ext_project) { create(:redmine_project) } - it "is true if used internal tracker" do + project = build(:empty_project) + expect(project.default_issues_tracker?).to be_truthy end it "is false if used other tracker" do - expect(ext_project.default_issues_tracker?).to be_falsey + # NOTE: The current nature of this factory requires persistence + project = create(:redmine_project) + + expect(project.default_issues_tracker?).to be_falsey end end describe '#external_issue_tracker' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:ext_project) { create(:redmine_project) } context 'on existing projects with no value for has_external_issue_tracker' do @@ -578,7 +578,7 @@ describe Project, models: true do end describe '#cache_has_external_issue_tracker' do - let(:project) { create(:project, has_external_issue_tracker: nil) } + let(:project) { create(:empty_project, has_external_issue_tracker: nil) } it 'stores true if there is any external_issue_tracker' do services = double(:service, external_issue_trackers: [RedmineService.new]) @@ -600,9 +600,9 @@ describe Project, models: true do end describe '#has_wiki?' do - let(:no_wiki_project) { create(:project, wiki_access_level: ProjectFeature::DISABLED, has_external_wiki: false) } - let(:wiki_enabled_project) { create(:project) } - let(:external_wiki_project) { create(:project, has_external_wiki: true) } + let(:no_wiki_project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED, has_external_wiki: false) } + let(:wiki_enabled_project) { create(:empty_project) } + let(:external_wiki_project) { create(:empty_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 @@ -612,7 +612,7 @@ describe Project, models: true do end describe '#external_wiki' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'with an active external wiki' do before do @@ -663,7 +663,7 @@ describe Project, models: true do end describe '#open_branches' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.protected_branches.create(name: 'master') @@ -685,7 +685,7 @@ describe Project, models: true do it 'counts stars from multiple users' do user1 = create :user user2 = create :user - project = create :project, :public + project = create(:empty_project, :public) expect(project.star_count).to eq(0) @@ -707,8 +707,8 @@ describe Project, models: true do it 'counts stars on the right project' do user = create :user - project1 = create :project, :public - project2 = create :project, :public + project1 = create(:empty_project, :public) + project2 = create(:empty_project, :public) expect(project1.star_count).to eq(0) expect(project2.star_count).to eq(0) @@ -740,7 +740,7 @@ describe Project, models: true do end describe '#avatar_type' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'is true if avatar is image' do project.update_attribute(:avatar, 'uploads/avatar.png') @@ -756,7 +756,7 @@ describe Project, models: true do describe '#avatar_url' do subject { project.avatar_url } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'When avatar file is uploaded' do before do @@ -791,7 +791,7 @@ describe Project, models: true do end describe '#pipeline_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:pipeline) { create_pipeline } shared_examples 'giving the correct pipeline' do @@ -825,13 +825,33 @@ describe Project, models: true do end describe '#builds_enabled' do - let(:project) { create :project } + let(:project) { create(:empty_project) } subject { project.builds_enabled } it { expect(project.builds_enabled?).to be_truthy } end + describe '.with_shared_runners' do + subject { Project.with_shared_runners } + + context 'when shared runners are enabled for project' do + let!(:project) { create(:empty_project, shared_runners_enabled: true) } + + it "returns a project" do + is_expected.to eq([project]) + end + end + + context 'when shared runners are disabled for project' do + let!(:project) { create(:empty_project, shared_runners_enabled: false) } + + it "returns an empty array" do + is_expected.to be_empty + end + end + end + describe '.cached_count', caching: true do let(:group) { create(:group, :public) } let!(:project1) { create(:empty_project, :public, group: group) } @@ -877,7 +897,7 @@ describe Project, models: true do end describe '.visible_to_user' do - let!(:project) { create(:project, :private) } + let!(:project) { create(:empty_project, :private) } let!(:user) { create(:user) } subject { described_class.visible_to_user(user) } @@ -974,8 +994,30 @@ describe Project, models: true do end end + describe '#shared_runners' do + let!(:runner) { create(:ci_runner, :shared) } + + subject { project.shared_runners } + + context 'when shared runners are enabled for project' do + let!(:project) { create(:empty_project, shared_runners_enabled: true) } + + it "returns a list of shared runners" do + is_expected.to eq([runner]) + end + end + + context 'when shared runners are disabled for project' do + let!(:project) { create(:empty_project, shared_runners_enabled: false) } + + it "returns a empty list" do + is_expected.to be_empty + end + end + end + describe '#visibility_level_allowed?' do - let(:project) { create(:project, :internal) } + let(:project) { create(:empty_project, :internal) } context 'when checking on non-forked project' do it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy } @@ -984,8 +1026,8 @@ describe Project, models: true do end context 'when checking on forked project' do - let(:project) { create(:project, :internal) } - let(:forked_project) { create(:project, forked_from_project: project) } + let(:project) { create(:empty_project, :internal) } + let(:forked_project) { create(:empty_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 } @@ -994,7 +1036,7 @@ describe Project, models: true do end describe '.search' do - let(:project) { create(:project, description: 'kitten mittens') } + let(:project) { create(:empty_project, description: 'kitten mittens') } it 'returns projects with a matching name' do expect(described_class.search(project.name)).to eq([project]) @@ -1052,7 +1094,7 @@ describe Project, models: true do end describe '#rename_repo' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:gitlab_shell) { Gitlab::Shell.new } before do @@ -1102,7 +1144,7 @@ describe Project, models: true do end describe '#expire_caches_before_rename' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repo) { double(:repo, exists?: true) } let(:wiki) { double(:wiki, exists?: true) } @@ -1123,7 +1165,7 @@ describe Project, models: true do end describe '.search_by_title' do - let(:project) { create(:project, name: 'kittens') } + let(:project) { create(:empty_project, name: 'kittens') } it 'returns projects with a matching name' do expect(described_class.search_by_title(project.name)).to eq([project]) @@ -1142,8 +1184,8 @@ describe Project, models: true 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 } + let(:private_project) { create :empty_project, :private, group: private_group } + let(:internal_project) { create :empty_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 } @@ -1155,7 +1197,7 @@ describe Project, models: true do end describe '#create_repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:shell) { Gitlab::Shell.new } before do @@ -1197,7 +1239,7 @@ describe Project, models: true do describe '#protected_branch?' do context 'existing project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'returns true when the branch matches a protected branch via direct match' do create(:protected_branch, project: project, name: "foo") @@ -1381,7 +1423,7 @@ describe Project, models: true do name: name) end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create_pipeline } context 'with many builds' do @@ -1461,7 +1503,7 @@ describe Project, models: true do end context 'not forked' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'schedules a RepositoryImportWorker job' do expect(RepositoryImportWorker).to receive(:perform_async).with(project.id) @@ -1472,19 +1514,19 @@ describe Project, models: true do end describe '#gitlab_project_import?' do - subject(:project) { build(:project, import_type: 'gitlab_project') } + subject(:project) { build(:empty_project, import_type: 'gitlab_project') } it { expect(project.gitlab_project_import?).to be true } end describe '#gitea_import?' do - subject(:project) { build(:project, import_type: 'gitea') } + subject(:project) { build(:empty_project, import_type: 'gitea') } it { expect(project.gitea_import?).to be true } end describe '#lfs_enabled?' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } shared_examples 'project overrides group' do it 'returns true when enabled in project' do @@ -1546,7 +1588,7 @@ describe Project, models: true do end describe '#change_head' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'calls the before_change_head and after_change_head methods' do expect(project.repository).to receive(:before_change_head) @@ -1574,7 +1616,7 @@ describe Project, models: true do end describe '#pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1596,7 +1638,7 @@ describe Project, models: true do end describe '#increment_pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1610,7 +1652,7 @@ describe Project, models: true do end describe '#reset_pushes_since_gc' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } after do project.reset_pushes_since_gc @@ -1626,7 +1668,7 @@ describe Project, models: true do end describe '#environments_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } context 'tagged deployment' do @@ -1678,7 +1720,7 @@ describe Project, models: true do end describe '#environments_recently_updated_on_branch' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } context 'when last deployment to environment is the most recent one' do diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 0475cecaa2d..942eeab251d 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -265,10 +265,10 @@ describe ProjectTeam, models: true 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) } + let(:personal_project) { create(:empty_project, namespace: developer.namespace) } + let(:group_project) { create(:empty_project, namespace: group) } + let(:members_project) { create(:empty_project) } + let(:shared_project) { create(:empty_project) } before do group.add_master(master) @@ -330,7 +330,7 @@ describe ProjectTeam, models: true do reporter = create(:user) promoted_guest = create(:user) guest = create(:user) - project = create(:project) + project = create(:empty_project) project.add_master(master) project.add_reporter(reporter) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 99ca53938c8..829b69093c9 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -4,7 +4,7 @@ describe Repository, models: true do include RepoHelpers TestBlob = Struct.new(:name) - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } @@ -90,6 +90,30 @@ describe Repository, models: true do it { is_expected.to eq(['v1.1.0', 'v1.0.0']) } end + + context 'annotated tag pointing to a blob' do + let(:annotated_tag_name) { 'annotated-tag' } + + subject { repository.tags_sorted_by('updated_asc').map(&:name) } + + before do + options = { message: 'test tag message\n', + tagger: { name: 'John Smith', email: 'john@gmail.com' } } + repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options) + + double_first = double(committed_date: Time.now - 1.second) + double_last = double(committed_date: Time.now) + + allow(tag_a).to receive(:dereferenced_target).and_return(double_last) + allow(tag_b).to receive(:dereferenced_target).and_return(double_first) + end + + it { is_expected.to eq(['v1.1.0', 'v1.0.0', annotated_tag_name]) } + + after do + repository.rugged.tags.delete(annotated_tag_name) + end + end end end diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 8481a9bef16..dd2a5109abc 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -14,7 +14,7 @@ describe Route, models: true do it { is_expected.to validate_uniqueness_of(:path) } end - describe '#rename_children' do + describe '#rename_descendants' do let!(:nested_group) { create(:group, path: "test", parent: group) } let!(:deep_nested_group) { create(:group, path: "foo", parent: nested_group) } let!(:similar_group) { create(:group, path: 'gitlab-org') } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 691511cd93f..0e2f07e945f 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -12,7 +12,7 @@ describe Service, models: true do end describe "Testable" do - let(:project) { create :project } + let(:project) { create(:project, :repository) } before do allow(@service).to receive(:project).and_return(project) @@ -35,7 +35,7 @@ describe Service, models: true do end describe "With commits" do - let(:project) { create :project } + let(:project) { create(:project, :repository) } before do allow(@service).to receive(:project).and_return(project) @@ -60,7 +60,7 @@ describe Service, models: true do api_key: '123456789' }) end - let(:project) { create(:project) } + let(:project) { create(:empty_project) } describe 'is prefilled for projects pushover service' do it "has all fields prefilled" do @@ -79,7 +79,7 @@ describe Service, models: true do describe "{property}_changed?" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -119,7 +119,7 @@ describe Service, models: true do describe "{property}_touched?" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -159,7 +159,7 @@ describe Service, models: true do describe "{property}_was" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -199,7 +199,7 @@ describe Service, models: true do describe 'initialize service with no properties' do let(:service) do GitlabIssueTrackerService.create( - project: create(:project), + project: create(:empty_project), title: 'random title' ) end @@ -214,7 +214,7 @@ describe Service, models: true do end describe "callbacks" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let!(:service) do RedmineService.new( project: project, diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 7425a897769..219ab1989ea 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -42,7 +42,7 @@ describe Snippet, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(snippet.to_reference(another_project)).to eq "sample-project$1" end end @@ -55,7 +55,7 @@ describe Snippet, models: true do end it 'still returns shortest reference when project arg present' do - another_project = build(:project, name: 'another-project') + another_project = build(:empty_project, name: 'another-project') expect(snippet.to_reference(another_project)).to eq "$1" end end @@ -173,7 +173,7 @@ describe Snippet, models: true do end describe '#participants' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:snippet) { create(:snippet, content: 'foo', project: project) } let!(:note1) do diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index 623b82c01d8..8017d1c3324 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Todo, models: true do - let(:project) { create(:project) } - let(:commit) { project.commit } let(:issue) { create(:issue) } describe 'relationships' do @@ -82,6 +80,9 @@ describe Todo, models: true do describe '#target' do context 'for commits' do + let(:project) { create(:project, :repository) } + let(:commit) { project.commit } + it 'returns an instance of Commit when exists' do subject.project = project subject.target_type = 'Commit' @@ -109,6 +110,9 @@ describe Todo, models: true do describe '#target_reference' do it 'returns the short commit id for commits' do + project = create(:project, :repository) + commit = project.commit + subject.project = project subject.target_type = 'Commit' subject.commit_id = commit.id diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb index 0737999e125..a87983b7492 100644 --- a/spec/models/tree_spec.rb +++ b/spec/models/tree_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Tree, models: true do - let(:repository) { create(:project).repository } + let(:repository) { create(:project, :repository).repository } let(:sha) { repository.root_ref } subject { described_class.new(repository, '54fcc214') } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8b20ee81614..6ca5ad747d1 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -48,7 +48,7 @@ describe User, models: true do describe '#project_members' do it 'does not include project memberships for which user is a requester' do user = create(:user) - project = create(:project, :public, :access_requestable) + project = create(:empty_project, :public, :access_requestable) project.request_access(user) expect(user.project_members).to be_empty @@ -386,13 +386,15 @@ describe User, models: true do describe 'projects' do before do - @user = create :user - @project = create :project, namespace: @user.namespace - @project_2 = create :project, group: create(:group) # Grant MASTER access to the user - @project_3 = create :project, group: create(:group) # Grant DEVELOPER access to the user + @user = create(:user) - @project_2.team << [@user, :master] - @project_3.team << [@user, :developer] + @project = create(:empty_project, namespace: @user.namespace) + @project_2 = create(:empty_project, group: create(:group)) do |project| + project.add_master(@user) + end + @project_3 = create(:empty_project, group: create(:group)) do |project| + project.add_developer(@user) + end end it { expect(@user.authorized_projects).to include(@project) } @@ -435,7 +437,7 @@ describe User, models: true do describe 'namespaced' do before do @user = create :user - @project = create :project, namespace: @user.namespace + @project = create(:empty_project, namespace: @user.namespace) end it { expect(@user.several_namespaces?).to be_falsey } @@ -517,7 +519,7 @@ describe User, models: true do before do User.delete_all @user = create :user - @project = create :project + @project = create(:empty_project) end it { expect(User.not_in_project(@project)).to include(@user, @project.owner) } @@ -795,14 +797,14 @@ describe User, models: true do describe '#avatar_type' do let(:user) { create(:user) } - it "is true if avatar is image" do + it 'is true if avatar is image' do user.update_attribute(:avatar, 'uploads/avatar.png') expect(user.avatar_type).to be_truthy end - it "is false if avatar is html page" do + it 'is false if avatar is html page' do user.update_attribute(:avatar, 'uploads/avatar.html') - expect(user.avatar_type).to eq(["only images allowed"]) + expect(user.avatar_type).to eq(['only images allowed']) end end @@ -924,11 +926,11 @@ describe User, models: true do end end - describe "#starred?" do - it "determines if user starred a project" do + describe '#starred?' do + it 'determines if user starred a project' do user = create :user - project1 = create :project, :public - project2 = create :project, :public + project1 = create(:empty_project, :public) + project2 = create(:empty_project, :public) expect(user.starred?(project1)).to be_falsey expect(user.starred?(project2)).to be_falsey @@ -951,10 +953,10 @@ describe User, models: true do end end - describe "#toggle_star" do - it "toggles stars" do + describe '#toggle_star' do + it 'toggles stars' do user = create :user - project = create :project, :public + project = create(:empty_project, :public) expect(user.starred?(project)).to be_falsey user.toggle_star(project) @@ -964,39 +966,52 @@ describe User, models: true do end end - describe "#sort" do + describe '#sort' do before do User.delete_all @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha' @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega' + @user2 = create :user, created_at: Date.today - 2, last_sign_in_at: nil, name: 'Beta' end - it "sorts users by the recent sign-in time" do - expect(User.sort('recent_sign_in').first).to eq(@user) + context 'when sort by recent_sign_in' do + it 'sorts users by the recent sign-in time' do + expect(User.sort('recent_sign_in').first).to eq(@user) + end + + it 'pushes users who never signed in to the end' do + expect(User.sort('recent_sign_in').third).to eq(@user2) + end end - it "sorts users by the oldest sign-in time" do - expect(User.sort('oldest_sign_in').first).to eq(@user1) + context 'when sort by oldest_sign_in' do + it 'sorts users by the oldest sign-in time' do + expect(User.sort('oldest_sign_in').first).to eq(@user1) + end + + it 'pushes users who never signed in to the end' do + expect(User.sort('oldest_sign_in').third).to eq(@user2) + end end - it "sorts users in descending order by their creation time" do + it 'sorts users in descending order by their creation time' do expect(User.sort('created_desc').first).to eq(@user) end - it "sorts users in ascending order by their creation time" do - expect(User.sort('created_asc').first).to eq(@user1) + it 'sorts users in ascending order by their creation time' do + expect(User.sort('created_asc').first).to eq(@user2) end - it "sorts users by id in descending order when nil is passed" do - expect(User.sort(nil).first).to eq(@user1) + it 'sorts users by id in descending order when nil is passed' do + expect(User.sort(nil).first).to eq(@user2) end end describe "#contributed_projects" do subject { create(:user) } - let!(:project1) { create(:project) } - let!(:project2) { create(:project, forked_from_project: project3) } - let!(:project3) { create(:project) } + let!(:project1) { create(:empty_project) } + let!(:project2) { create(:empty_project, forked_from_project: project3) } + let!(:project3) { create(:empty_project) } let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) } let!(:push_event) { create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject) } let!(:merge_event) { create(:event, action: Event::CREATED, project: project3, target: merge_request, author: subject) } @@ -1038,8 +1053,8 @@ describe User, models: true do describe "#recent_push" do subject { create(:user) } - let!(:project1) { create(:project) } - let!(:project2) { create(:project, forked_from_project: project1) } + let!(:project1) { create(:project, :repository) } + let!(:project2) { create(:project, :repository, forked_from_project: project1) } let!(:push_data) do Gitlab::DataBuilder::Push.build_sample(project2, subject) end @@ -1113,7 +1128,7 @@ describe User, models: true do it "includes user's personal projects" do user = create(:user) - project = create(:project, :private, namespace: user.namespace) + project = create(:empty_project, :private, namespace: user.namespace) expect(user.authorized_projects).to include(project) end @@ -1121,7 +1136,7 @@ describe User, models: true do it "includes personal projects user has been given access to" do user1 = create(:user) user2 = create(:user) - project = create(:project, :private, namespace: user1.namespace) + project = create(:empty_project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] @@ -1130,7 +1145,7 @@ describe User, models: true do it "includes projects of groups user has been added to" do group = create(:group) - project = create(:project, group: group) + project = create(:empty_project, group: group) user = create(:user) group.add_developer(user) @@ -1140,7 +1155,7 @@ describe User, models: true do it "does not include projects of groups user has been removed from" do group = create(:group) - project = create(:project, group: group) + project = create(:empty_project, group: group) user = create(:user) member = group.add_developer(user) @@ -1152,7 +1167,7 @@ describe User, models: true do it "includes projects shared with user's group" do user = create(:user) - project = create(:project, :private) + project = create(:empty_project, :private) group = create(:group) group.add_reporter(user) @@ -1164,7 +1179,7 @@ describe User, models: true do it "does not include destroyed projects user had access to" do user1 = create(:user) user2 = create(:user) - project = create(:project, :private, namespace: user1.namespace) + project = create(:empty_project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] expect(user2.authorized_projects).to include(project) @@ -1175,7 +1190,7 @@ describe User, models: true do it "does not include projects of destroyed groups user had access to" do group = create(:group) - project = create(:project, namespace: group) + project = create(:empty_project, namespace: group) user = create(:user) group.add_developer(user) @@ -1190,14 +1205,9 @@ describe User, models: true do let(:user) { create(:user) } it 'includes projects for which the user access level is above or equal to reporter' do - create(:project) - reporter_project = create(:project) - developer_project = create(:project) - master_project = create(:project) - - reporter_project.team << [user, :reporter] - developer_project.team << [user, :developer] - master_project.team << [user, :master] + reporter_project = create(:empty_project) { |p| p.add_reporter(user) } + developer_project = create(:empty_project) { |p| p.add_developer(user) } + master_project = create(:empty_project) { |p| p.add_master(user) } expect(user.projects_where_can_admin_issues.to_a).to eq([master_project, developer_project, reporter_project]) expect(user.can?(:admin_issue, master_project)).to eq(true) @@ -1206,10 +1216,8 @@ describe User, models: true do end it 'does not include for which the user access level is below reporter' do - project = create(:project) - guest_project = create(:project) - - guest_project.team << [user, :guest] + project = create(:empty_project) + guest_project = create(:empty_project) { |p| p.add_guest(user) } expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, guest_project)).to eq(false) @@ -1217,15 +1225,14 @@ describe User, models: true do end it 'does not include archived projects' do - project = create(:project) - project.update_attributes(archived: true) + project = create(:empty_project, :archived) expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, project)).to eq(false) end it 'does not include projects for which issues are disabled' do - project = create(:project, issues_access_level: ProjectFeature::DISABLED) + project = create(:empty_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) @@ -1241,7 +1248,7 @@ describe User, models: true do end context 'without any projects' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'does not load' do expect(user.ci_authorized_runners).to be_empty @@ -1250,7 +1257,7 @@ describe User, models: true do context 'with personal projects runners' do let(:namespace) { create(:namespace, owner: user) } - let(:project) { create(:project, namespace: namespace) } + let(:project) { create(:empty_project, namespace: namespace) } it 'loads' do expect(user.ci_authorized_runners).to contain_exactly(runner) @@ -1281,7 +1288,7 @@ describe User, models: true do context 'with groups projects runners' do let(:group) { create(:group) } - let(:project) { create(:project, group: group) } + let(:project) { create(:empty_project, group: group) } def add_user(access) group.add_user(user, access) @@ -1291,7 +1298,7 @@ describe User, models: true do end context 'with other projects runners' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } def add_user(access) project.team << [user, access] @@ -1321,8 +1328,8 @@ describe User, models: true do end describe '#projects_with_reporter_access_limited_to' do - let(:project1) { create(:project) } - let(:project2) { create(:project) } + let(:project1) { create(:empty_project) } + let(:project2) { create(:empty_project) } let(:user) { create(:user) } before do @@ -1356,6 +1363,39 @@ describe User, models: true do end end + describe '#nested_groups' do + let!(:user) { create(:user) } + let!(:group) { create(:group) } + let!(:nested_group) { create(:group, parent: group) } + + before do + group.add_owner(user) + + # Add more data to ensure method does not include wrong groups + create(:group).add_owner(create(:user)) + end + + it { expect(user.nested_groups).to eq([nested_group]) } + end + + describe '#nested_projects' do + let!(:user) { create(:user) } + let!(:group) { create(:group) } + let!(:nested_group) { create(:group, parent: group) } + let!(:project) { create(:empty_project, namespace: group) } + let!(:nested_project) { create(:empty_project, namespace: nested_group) } + + before do + group.add_owner(user) + + # Add more data to ensure method does not include wrong projects + other_project = create(:empty_project, namespace: create(:group, :nested)) + other_project.add_developer(create(:user)) + end + + it { expect(user.nested_projects).to eq([nested_project]) } + end + describe '#refresh_authorized_projects', redis: true do let(:project1) { create(:empty_project) } let(:project2) { create(:empty_project) } |