diff options
author | Felipe Artur <felipefac@gmail.com> | 2016-03-16 20:16:42 -0300 |
---|---|---|
committer | Felipe Artur <felipefac@gmail.com> | 2016-03-16 20:16:42 -0300 |
commit | 44c127447b5a3cfc7aaea6f19e18baf9f42ad500 (patch) | |
tree | f386dbb06fec8c5fdec92812394ac63cf67183a0 /spec/models | |
parent | ec20fdf366843e60ed30abb5322c3c1b8f471b4a (diff) | |
parent | 59064aeeef8562a87d4d03efa9b11012a007e261 (diff) | |
download | gitlab-ce-44c127447b5a3cfc7aaea6f19e18baf9f42ad500.tar.gz |
Merge 4009-external-users into issue_12658
Diffstat (limited to 'spec/models')
-rw-r--r-- | spec/models/build_spec.rb | 66 | ||||
-rw-r--r-- | spec/models/ci/commit_spec.rb | 44 | ||||
-rw-r--r-- | spec/models/ci/runner_spec.rb | 28 | ||||
-rw-r--r-- | spec/models/concerns/issuable_spec.rb | 89 | ||||
-rw-r--r-- | spec/models/concerns/subscribable_spec.rb | 57 | ||||
-rw-r--r-- | spec/models/group_spec.rb | 26 | ||||
-rw-r--r-- | spec/models/hooks/service_hook_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/hooks/web_hook_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 6 | ||||
-rw-r--r-- | spec/models/milestone_spec.rb | 30 | ||||
-rw-r--r-- | spec/models/namespace_spec.rb | 29 | ||||
-rw-r--r-- | spec/models/note_spec.rb | 82 | ||||
-rw-r--r-- | spec/models/project_group_link_spec.rb | 17 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 96 | ||||
-rw-r--r-- | spec/models/project_team_spec.rb | 44 | ||||
-rw-r--r-- | spec/models/snippet_spec.rb | 44 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 87 |
17 files changed, 599 insertions, 150 deletions
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index e3d3d453653..b7457808040 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -9,7 +9,7 @@ describe Ci::Build, models: true do it { is_expected.to respond_to :trace_html } - describe :first_pending do + describe '#first_pending' do let(:first) { FactoryGirl.create :ci_build, commit: commit, status: 'pending', created_at: Date.yesterday } let(:second) { FactoryGirl.create :ci_build, commit: commit, status: 'pending' } before { first; second } @@ -19,7 +19,7 @@ describe Ci::Build, models: true do it('returns with the first pending build') { is_expected.to eq(first) } end - describe :create_from do + describe '#create_from' do before do build.status = 'success' build.save @@ -33,7 +33,7 @@ describe Ci::Build, models: true do end end - describe :ignored? do + describe '#ignored?' do subject { build.ignored? } context 'if build is not allowed to fail' do @@ -69,7 +69,7 @@ describe Ci::Build, models: true do end end - describe :trace do + describe '#trace' do subject { build.trace_html } it { is_expected.to be_empty } @@ -101,7 +101,7 @@ describe Ci::Build, models: true do # it { is_expected.to eq(commit.project.timeout) } # end - describe :options do + describe '#options' do let(:options) do { image: "ruby:2.1", @@ -122,25 +122,25 @@ describe Ci::Build, models: true do # it { is_expected.to eq(project.allow_git_fetch) } # end - describe :project do + describe '#project' do subject { build.project } it { is_expected.to eq(commit.project) } end - describe :project_id do + describe '#project_id' do subject { build.project_id } it { is_expected.to eq(commit.project_id) } end - describe :project_name do + describe '#project_name' do subject { build.project_name } it { is_expected.to eq(project.name) } end - describe :extract_coverage do + describe '#extract_coverage' do context 'valid content & regex' do subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') } @@ -172,7 +172,7 @@ describe Ci::Build, models: true do end end - describe :variables do + describe '#variables' do context 'returns variables' do subject { build.variables } @@ -242,7 +242,7 @@ describe Ci::Build, models: true do end end - describe :can_be_served? do + describe '#can_be_served?' do let(:runner) { FactoryGirl.create :ci_runner } before { build.project.runners << runner } @@ -277,7 +277,7 @@ describe Ci::Build, models: true do end end - describe :any_runners_online? do + describe '#any_runners_online?' do subject { build.any_runners_online? } context 'when no runners' do @@ -312,8 +312,8 @@ describe Ci::Build, models: true do end end - describe :show_warning? do - subject { build.show_warning? } + describe '#stuck?' do + subject { build.stuck? } %w(pending).each do |state| context "if commit_status.status is #{state}" do @@ -343,35 +343,7 @@ describe Ci::Build, models: true do end end - describe :artifacts_download_url do - subject { build.artifacts_download_url } - - context 'artifacts file does not exist' do - before { build.update_attributes(artifacts_file: nil) } - it { is_expected.to be_nil } - end - - context 'artifacts file exists' do - let(:build) { create(:ci_build, :artifacts) } - it { is_expected.to_not be_nil } - end - end - - describe :artifacts_browse_url do - subject { build.artifacts_browse_url } - - it "should be nil if artifacts browser is unsupported" do - allow(build).to receive(:artifacts_metadata?).and_return(false) - is_expected.to be_nil - end - - it 'should not be nil if artifacts browser is supported' do - allow(build).to receive(:artifacts_metadata?).and_return(true) - is_expected.to_not be_nil - end - end - - describe :artifacts? do + describe '#artifacts?' do subject { build.artifacts? } context 'artifacts archive does not exist' do @@ -386,7 +358,7 @@ describe Ci::Build, models: true do end - describe :artifacts_metadata? do + describe '#artifacts_metadata?' do subject { build.artifacts_metadata? } context 'artifacts metadata does not exist' do it { is_expected.to be_falsy } @@ -398,7 +370,7 @@ describe Ci::Build, models: true do end end - describe :repo_url do + describe '#repo_url' do let(:build) { FactoryGirl.create :ci_build } let(:project) { build.project } @@ -412,7 +384,7 @@ describe Ci::Build, models: true do it { is_expected.to include(project.web_url[7..-1]) } end - describe :depends_on_builds do + describe '#depends_on_builds' do let!(:build) { FactoryGirl.create :ci_build, commit: commit, name: 'build', stage_idx: 0, stage: 'build' } let!(:rspec_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rspec', stage_idx: 1, stage: 'test' } let!(:rubocop_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rubocop', stage_idx: 1, stage: 'test' } @@ -444,7 +416,7 @@ describe Ci::Build, models: true do created_at: created_at) end - describe :merge_request do + describe '#merge_request' do context 'when a MR has a reference to the commit' do before do @merge_request = create_mr(build, commit, factory: :merge_request) diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index 4dc309a4255..412842337ba 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -32,50 +32,6 @@ describe Ci::Commit, models: true do it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :short_sha } - describe :ordered do - let(:project) { FactoryGirl.create :empty_project } - - it 'returns ordered list of commits' do - commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project - commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project - expect(project.ci_commits.ordered).to eq([commit2, commit1]) - end - - it 'returns commits ordered by committed_at and id, with nulls last' do - commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project - commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project - commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project - commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project - expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1]) - end - end - - describe :last_build do - subject { commit.last_build } - before do - @first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday - @second = FactoryGirl.create :ci_build, commit: commit - end - - it { is_expected.to be_a(Ci::Build) } - it('returns with the most recently created build') { is_expected.to eq(@second) } - end - - describe :retry do - before do - @first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday - @second = FactoryGirl.create :ci_build, commit: commit - end - - it "creates only a new build" do - expect(commit.builds.count(:all)).to eq 2 - expect(commit.statuses.count(:all)).to eq 2 - commit.retry - expect(commit.builds.count(:all)).to eq 3 - expect(commit.statuses.count(:all)).to eq 3 - end - end - describe :valid_commit_sha do context 'commit.sha can not start with 00000000' do before do diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index e891838672e..25e9e5eca48 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -132,4 +132,32 @@ describe Ci::Runner, models: true do expect(runner.belongs_to_one_project?).to be_truthy end end + + describe '#search' do + let(:runner) { create(:ci_runner, token: '123abc') } + + it 'returns runners with a matching token' do + expect(described_class.search(runner.token)).to eq([runner]) + end + + it 'returns runners with a partially matching token' do + expect(described_class.search(runner.token[0..2])).to eq([runner]) + end + + it 'returns runners with a matching token regardless of the casing' do + expect(described_class.search(runner.token.upcase)).to eq([runner]) + end + + it 'returns runners with a matching description' do + expect(described_class.search(runner.description)).to eq([runner]) + end + + it 'returns runners with a partially matching description' do + expect(described_class.search(runner.description[0..2])).to eq([runner]) + end + + it 'returns runners with a matching description regardless of the casing' do + expect(described_class.search(runner.description.upcase)).to eq([runner]) + end + end end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 600089802b2..be29b6d66ff 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -32,9 +32,54 @@ describe Issue, "Issuable" do describe ".search" do let!(:searchable_issue) { create(:issue, title: "Searchable issue") } - it "matches by title" do + it 'returns notes with a matching title' do + expect(described_class.search(searchable_issue.title)). + to eq([searchable_issue]) + end + + it 'returns notes with a partially matching title' do expect(described_class.search('able')).to eq([searchable_issue]) end + + it 'returns notes with a matching title regardless of the casing' do + expect(described_class.search(searchable_issue.title.upcase)). + to eq([searchable_issue]) + end + end + + describe ".full_search" do + let!(:searchable_issue) do + create(:issue, title: "Searchable issue", description: 'kittens') + end + + it 'returns notes with a matching title' do + expect(described_class.full_search(searchable_issue.title)). + to eq([searchable_issue]) + end + + it 'returns notes with a partially matching title' do + expect(described_class.full_search('able')).to eq([searchable_issue]) + end + + it 'returns notes with a matching title regardless of the casing' do + expect(described_class.full_search(searchable_issue.title.upcase)). + to eq([searchable_issue]) + end + + it 'returns notes with a matching description' do + expect(described_class.full_search(searchable_issue.description)). + to eq([searchable_issue]) + end + + it 'returns notes with a partially matching description' do + expect(described_class.full_search(searchable_issue.description)). + to eq([searchable_issue]) + end + + it 'returns notes with a matching description regardless of the casing' do + expect(described_class.full_search(searchable_issue.description.upcase)). + to eq([searchable_issue]) + end end describe "#today?" do @@ -68,6 +113,48 @@ describe Issue, "Issuable" do end end + describe '#subscribed?' do + context 'user is not a participant in the issue' do + before { allow(issue).to receive(:participants).with(user).and_return([]) } + + it 'returns false when no subcription exists' do + expect(issue.subscribed?(user)).to be_falsey + end + + it 'returns true when a subcription exists and subscribed is true' do + issue.subscriptions.create(user: user, subscribed: true) + + expect(issue.subscribed?(user)).to be_truthy + end + + it 'returns false when a subcription exists and subscribed is false' do + issue.subscriptions.create(user: user, subscribed: false) + + expect(issue.subscribed?(user)).to be_falsey + end + end + + context 'user is a participant in the issue' do + before { allow(issue).to receive(:participants).with(user).and_return([user]) } + + it 'returns false when no subcription exists' do + expect(issue.subscribed?(user)).to be_truthy + end + + it 'returns true when a subcription exists and subscribed is true' do + issue.subscriptions.create(user: user, subscribed: true) + + expect(issue.subscribed?(user)).to be_truthy + end + + it 'returns false when a subcription exists and subscribed is false' do + issue.subscriptions.create(user: user, subscribed: false) + + expect(issue.subscribed?(user)).to be_falsey + end + end + end + describe "#to_hook_data" do let(:data) { issue.to_hook_data(user) } let(:project) { issue.project } diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb new file mode 100644 index 00000000000..e31fdb0bffb --- /dev/null +++ b/spec/models/concerns/subscribable_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe Subscribable, 'Subscribable' do + let(:resource) { create(:issue) } + let(:user) { create(:user) } + + describe '#subscribed?' do + it 'returns false when no subcription exists' do + expect(resource.subscribed?(user)).to be_falsey + end + + it 'returns true when a subcription exists and subscribed is true' do + resource.subscriptions.create(user: user, subscribed: true) + + expect(resource.subscribed?(user)).to be_truthy + end + + it 'returns false when a subcription exists and subscribed is false' do + resource.subscriptions.create(user: user, subscribed: false) + + expect(resource.subscribed?(user)).to be_falsey + end + end + describe '#subscribers' do + it 'returns [] when no subcribers exists' do + expect(resource.subscribers).to be_empty + end + + it 'returns the subscribed users' do + resource.subscriptions.create(user: user, subscribed: true) + resource.subscriptions.create(user: create(:user), subscribed: false) + + expect(resource.subscribers).to eq [user] + end + end + + describe '#toggle_subscription' do + it 'toggles the current subscription state for the given user' do + expect(resource.subscribed?(user)).to be_falsey + + resource.toggle_subscription(user) + + expect(resource.subscribed?(user)).to be_truthy + end + end + + describe '#unsubscribe' do + it 'unsubscribes the given current user' do + resource.subscriptions.create(user: user, subscribed: true) + expect(resource.subscribed?(user)).to be_truthy + + resource.unsubscribe(user) + + expect(resource.subscribed?(user)).to be_falsey + end + end +end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 25aa77dc4e8..135d298e10f 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -121,4 +121,30 @@ describe Group, models: true do expect(group.avatar_type).to eq(["only images allowed"]) end end + + describe '.search' do + it 'returns groups with a matching name' do + expect(described_class.search(group.name)).to eq([group]) + end + + it 'returns groups with a partially matching name' do + expect(described_class.search(group.name[0..2])).to eq([group]) + end + + it 'returns groups with a matching name regardless of the casing' do + expect(described_class.search(group.name.upcase)).to eq([group]) + end + + it 'returns groups with a matching path' do + expect(described_class.search(group.path)).to eq([group]) + end + + it 'returns groups with a partially matching path' do + expect(described_class.search(group.path[0..2])).to eq([group]) + end + + it 'returns groups with a matching path regardless of the casing' do + expect(described_class.search(group.path.upcase)).to eq([group]) + end + end end diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 1455661485b..f800f415bd2 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -31,7 +31,7 @@ describe ServiceHook, models: true do WebMock.stub_request(:post, @service_hook.url) end - it "POSTs to the web hook URL" do + it "POSTs to the webhook URL" do @service_hook.execute(@data) expect(WebMock).to have_requested(:post, @service_hook.url).with( headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Service Hook' } diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 6ea99952a8f..04bc2dcfb16 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -52,7 +52,7 @@ describe WebHook, models: true do WebMock.stub_request(:post, @project_hook.url) end - it "POSTs to the web hook URL" do + it "POSTs to the webhook URL" do @project_hook.execute(@data, 'push_hooks') expect(WebMock).to have_requested(:post, @project_hook.url).with( headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 59c40922abb..8bf68013fd2 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -80,6 +80,12 @@ describe MergeRequest, models: true do it { is_expected.to respond_to(:merge_when_build_succeeds) } end + describe '.in_projects' do + it 'returns the merge requests for a set of projects' do + expect(described_class.in_projects(Project.all)).to eq([subject]) + end + end + describe '#to_reference' do it 'returns a String reference to the object' do expect(subject.to_reference).to eq "!#{subject.iid}" diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 28f13100d15..de1757bf67a 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -181,4 +181,34 @@ describe Milestone, models: true do expect(issue4.position).to eq(42) end end + + describe '.search' do + let(:milestone) { create(:milestone, title: 'foo', description: 'bar') } + + it 'returns milestones with a matching title' do + expect(described_class.search(milestone.title)).to eq([milestone]) + end + + it 'returns milestones with a partially matching title' do + expect(described_class.search(milestone.title[0..2])).to eq([milestone]) + end + + it 'returns milestones with a matching title regardless of the casing' do + expect(described_class.search(milestone.title.upcase)).to eq([milestone]) + end + + it 'returns milestones with a matching description' do + expect(described_class.search(milestone.description)).to eq([milestone]) + end + + it 'returns milestones with a partially matching description' do + expect(described_class.search(milestone.description[0..2])). + to eq([milestone]) + end + + it 'returns milestones with a matching description regardless of the casing' do + expect(described_class.search(milestone.description.upcase)). + to eq([milestone]) + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index e0b3290e416..3c3a580942a 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -41,13 +41,32 @@ describe Namespace, models: true do it { expect(namespace.human_name).to eq(namespace.owner_name) } end - describe :search do - before do - @namespace = create :namespace + describe '.search' do + let(:namespace) { create(:namespace) } + + it 'returns namespaces with a matching name' do + expect(described_class.search(namespace.name)).to eq([namespace]) + end + + it 'returns namespaces with a partially matching name' do + expect(described_class.search(namespace.name[0..2])).to eq([namespace]) + end + + it 'returns namespaces with a matching name regardless of the casing' do + expect(described_class.search(namespace.name.upcase)).to eq([namespace]) + end + + it 'returns namespaces with a matching path' do + expect(described_class.search(namespace.path)).to eq([namespace]) end - it { expect(Namespace.search(@namespace.path)).to eq([@namespace]) } - it { expect(Namespace.search('unknown')).to eq([]) } + it 'returns namespaces with a partially matching path' do + expect(described_class.search(namespace.path[0..2])).to eq([namespace]) + end + + it 'returns namespaces with a matching path regardless of the casing' do + expect(described_class.search(namespace.path.upcase)).to eq([namespace]) + end end describe :move_dir do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 33085dac4ea..6b18936edb1 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -140,13 +140,19 @@ describe Note, models: true do end end - describe :search do - let!(:note) { create(:note, note: "WoW") } + describe '.search' do + let(:note) { create(:note, note: 'WoW') } - it { expect(Note.search('wow')).to include(note) } + it 'returns notes with matching content' do + expect(described_class.search(note.note)).to eq([note]) + end + + it 'returns notes with matching content regardless of the casing' do + expect(described_class.search('WOW')).to eq([note]) + end end - describe :grouped_awards do + describe '.grouped_awards' do before do create :note, note: "smile", is_award: true create :note, note: "smile", is_award: true @@ -163,6 +169,66 @@ describe Note, models: true do end end + describe '#active?' do + it 'is always true when the note has no associated diff' do + note = build(:note) + + expect(note).to receive(:diff).and_return(nil) + + expect(note).to be_active + end + + it 'is never true when the note has no noteable associated' do + note = build(:note) + + expect(note).to receive(:diff).and_return(double) + expect(note).to receive(:noteable).and_return(nil) + + expect(note).not_to be_active + end + + it 'returns the memoized value if defined' do + note = build(:note) + + expect(note).to receive(:diff).and_return(double) + expect(note).to receive(:noteable).and_return(double) + + note.instance_variable_set(:@active, 'foo') + expect(note).not_to receive(:find_noteable_diff) + + expect(note.active?).to eq 'foo' + end + + context 'for a merge request noteable' do + it 'is false when noteable has no matching diff' do + merge = build_stubbed(:merge_request, :simple) + note = build(:note, noteable: merge) + + allow(note).to receive(:diff).and_return(double) + expect(note).to receive(:find_noteable_diff).and_return(nil) + + expect(note).not_to be_active + end + + it 'is true when noteable has a matching diff' do + merge = create(:merge_request, :simple) + + # Generate a real line_code value so we know it will match. We use a + # random line from a random diff just for funsies. + diff = merge.diffs.to_a.sample + line = Gitlab::Diff::Parser.new.parse(diff.diff.each_line).to_a.sample + code = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) + + # We're persisting in order to trigger the set_diff callback + note = create(:note, noteable: merge, line_code: code) + + # Make sure we don't get a false positive from a guard clause + expect(note).to receive(:find_noteable_diff).and_call_original + expect(note).to be_active + end + end + end + describe "editable?" do it "returns true" do note = build(:note) @@ -220,4 +286,12 @@ describe Note, models: true do expect(note.is_award?).to be_falsy end end + + describe 'clear_blank_line_code!' do + it 'clears a blank line code before validation' do + note = build(:note, line_code: ' ') + + expect { note.valid? }.to change(note, :line_code).to(nil) + end + end end diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb new file mode 100644 index 00000000000..2fa6715fcaf --- /dev/null +++ b/spec/models/project_group_link_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe ProjectGroupLink do + describe "Associations" do + it { should belong_to(:group) } + it { should belong_to(:project) } + end + + describe "Validation" do + let!(:project_group_link) { create(:project_group_link) } + + it { should validate_presence_of(:project_id) } + it { should validate_uniqueness_of(:group_id).scoped_to(:project_id).with_message(/already shared/) } + it { should validate_presence_of(:group_id) } + it { should validate_presence_of(:group_access) } + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9efaffbb577..7fd3726c6ad 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -582,21 +582,63 @@ describe Project, models: true do it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy } it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey } end + end - context 'when checking projects from groups' do - let(:private_group) { create(:group, visibility_level: 0) } - let(:internal_group) { create(:group, visibility_level: 10) } + describe '.search' do + let(:project) { create(:project, description: 'kitten mittens') } - let(:private_project) { create :project, group: private_group, visibility_level: Gitlab::VisibilityLevel::PRIVATE } - let(:internal_project) { create :project, group: internal_group, visibility_level: Gitlab::VisibilityLevel::INTERNAL } + it 'returns projects with a matching name' do + expect(described_class.search(project.name)).to eq([project]) + end - context 'when group is private project can not be internal' do - it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey } - end + it 'returns projects with a partially matching name' do + expect(described_class.search(project.name[0..2])).to eq([project]) + end - context 'when group is internal project can not be public' do - it { expect(internal_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey } - end + it 'returns projects with a matching name regardless of the casing' do + expect(described_class.search(project.name.upcase)).to eq([project]) + end + + it 'returns projects with a matching description' do + expect(described_class.search(project.description)).to eq([project]) + end + + it 'returns projects with a partially matching description' do + expect(described_class.search('kitten')).to eq([project]) + end + + it 'returns projects with a matching description regardless of the casing' do + expect(described_class.search('KITTEN')).to eq([project]) + end + + it 'returns projects with a matching path' do + expect(described_class.search(project.path)).to eq([project]) + end + + it 'returns projects with a partially matching path' do + expect(described_class.search(project.path[0..2])).to eq([project]) + end + + it 'returns projects with a matching path regardless of the casing' do + expect(described_class.search(project.path.upcase)).to eq([project]) + end + + it 'returns projects with a matching namespace name' do + expect(described_class.search(project.namespace.name)).to eq([project]) + end + + it 'returns projects with a partially matching namespace name' do + expect(described_class.search(project.namespace.name[0..2])).to eq([project]) + end + + it 'returns projects with a matching namespace name regardless of the casing' do + expect(described_class.search(project.namespace.name.upcase)).to eq([project]) + end + + it 'returns projects when eager loading namespaces' do + relation = described_class.all.includes(:namespace) + + expect(relation.search(project.namespace.name)).to eq([project]) end end @@ -662,4 +704,36 @@ describe Project, models: true do project.expire_caches_before_rename('foo') end end + + describe '.search_by_title' do + let(:project) { create(:project, name: 'kittens') } + + it 'returns projects with a matching name' do + expect(described_class.search_by_title(project.name)).to eq([project]) + end + + it 'returns projects with a partially matching name' do + expect(described_class.search_by_title('kitten')).to eq([project]) + end + + it 'returns projects with a matching name regardless of the casing' do + expect(described_class.search_by_title('KITTENS')).to eq([project]) + end + end + + context 'when checking projects from groups' do + let(:private_group) { create(:group, visibility_level: 0) } + let(:internal_group) { create(:group, visibility_level: 10) } + + let(:private_project) { create :project, group: private_group, visibility_level: Gitlab::VisibilityLevel::PRIVATE } + let(:internal_project) { create :project, group: internal_group, visibility_level: Gitlab::VisibilityLevel::INTERNAL } + + context 'when group is private project can not be internal' do + it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey } + end + + context 'when group is internal project can not be public' do + it { expect(internal_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PUBLIC)).to be_falsey } + end + end end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 7b63da005f0..bacb17a8883 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -67,6 +67,50 @@ describe ProjectTeam, models: true do end end + describe :max_invited_level do + let(:group) { create(:group) } + let(:project) { create(:empty_project) } + + before do + project.project_group_links.create( + group: group, + group_access: Gitlab::Access::DEVELOPER + ) + + group.add_user(master, Gitlab::Access::MASTER) + group.add_user(reporter, Gitlab::Access::REPORTER) + end + + it { expect(project.team.max_invited_level(master.id)).to eq(Gitlab::Access::DEVELOPER) } + it { expect(project.team.max_invited_level(reporter.id)).to eq(Gitlab::Access::REPORTER) } + it { expect(project.team.max_invited_level(nonmember.id)).to be_nil } + end + + describe :max_member_access do + let(:group) { create(:group) } + let(:project) { create(:empty_project) } + + before do + project.project_group_links.create( + group: group, + group_access: Gitlab::Access::DEVELOPER + ) + + group.add_user(master, Gitlab::Access::MASTER) + group.add_user(reporter, Gitlab::Access::REPORTER) + end + + it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) } + it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) } + it { expect(project.team.max_member_access(nonmember.id)).to be_nil } + + it "does not have an access" do + project.namespace.update(share_with_group_lock: true) + expect(project.team.max_member_access(master.id)).to be_nil + expect(project.team.max_member_access(reporter.id)).to be_nil + end + end + describe "#human_max_access" do it 'returns Master role' do user = create(:user) diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 7e5b5499aea..5077ac7b62b 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -59,4 +59,48 @@ describe Snippet, models: true do expect(snippet.to_reference(cross)).to eq "#{project.to_reference}$#{snippet.id}" end end + + describe '.search' do + let(:snippet) { create(:snippet) } + + it 'returns snippets with a matching title' do + expect(described_class.search(snippet.title)).to eq([snippet]) + end + + it 'returns snippets with a partially matching title' do + expect(described_class.search(snippet.title[0..2])).to eq([snippet]) + end + + it 'returns snippets with a matching title regardless of the casing' do + expect(described_class.search(snippet.title.upcase)).to eq([snippet]) + end + + it 'returns snippets with a matching file name' do + expect(described_class.search(snippet.file_name)).to eq([snippet]) + end + + it 'returns snippets with a partially matching file name' do + expect(described_class.search(snippet.file_name[0..2])).to eq([snippet]) + end + + it 'returns snippets with a matching file name regardless of the casing' do + expect(described_class.search(snippet.file_name.upcase)).to eq([snippet]) + end + end + + describe '#search_code' do + let(:snippet) { create(:snippet, content: 'class Foo; end') } + + it 'returns snippets with matching content' do + expect(described_class.search_code(snippet.content)).to eq([snippet]) + end + + it 'returns snippets with partially matching content' do + expect(described_class.search_code('class')).to eq([snippet]) + end + + it 'returns snippets with matching content regardless of the casing' do + expect(described_class.search_code('FOO')).to eq([snippet]) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 412101ac9f9..0ab7fd88ce6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -174,38 +174,26 @@ describe User, models: true do end end end - - describe 'avatar' do - it 'only validates when avatar is present and changed' do - user = build(:user, :with_avatar) - - user.avatar_crop_x = nil - user.avatar_crop_y = nil - user.avatar_crop_size = nil - - expect(user).not_to be_valid - expect(user.errors.keys). - to match_array %i(avatar_crop_x avatar_crop_y avatar_crop_size) - end - - it 'does not validate when avatar has not changed' do - user = create(:user, :with_avatar) - - expect { user.avatar_crop_x = nil }.not_to change(user, :valid?) - end - - it 'does not validate when avatar is not present' do - user = create(:user) - - expect { user.avatar_crop_y = nil }.not_to change(user, :valid?) - end - end end describe "Respond to" do it { is_expected.to respond_to(:is_admin?) } it { is_expected.to respond_to(:name) } it { is_expected.to respond_to(:private_token) } + it { is_expected.to respond_to(:external?) } + end + + describe 'before save hook' do + context 'when saving an external user' do + let(:user) { create(:user) } + let(:external_user) { create(:user, external: true) } + + it "sets other properties aswell" do + expect(external_user.can_create_team).to be_falsey + expect(external_user.can_create_group).to be_falsey + expect(external_user.projects_limit).to be 0 + end + end end describe '#confirm' do @@ -430,6 +418,7 @@ describe User, models: true do expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit) expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group) expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme) + expect(user.external).to be_falsey end end @@ -463,17 +452,43 @@ describe User, models: true do end end - describe 'search' do - let(:user1) { create(:user, username: 'James', email: 'james@testing.com') } - let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') } + describe '.search' do + let(:user) { create(:user) } + + it 'returns users with a matching name' do + expect(described_class.search(user.name)).to eq([user]) + end + + it 'returns users with a partially matching name' do + expect(described_class.search(user.name[0..2])).to eq([user]) + end + + it 'returns users with a matching name regardless of the casing' do + expect(described_class.search(user.name.upcase)).to eq([user]) + end + + it 'returns users with a matching Email' do + expect(described_class.search(user.email)).to eq([user]) + end + + it 'returns users with a partially matching Email' do + expect(described_class.search(user.email[0..2])).to eq([user]) + end + + it 'returns users with a matching Email regardless of the casing' do + expect(described_class.search(user.email.upcase)).to eq([user]) + end + + it 'returns users with a matching username' do + expect(described_class.search(user.username)).to eq([user]) + end + + it 'returns users with a partially matching username' do + expect(described_class.search(user.username[0..2])).to eq([user]) + end - it "should be case insensitive" do - expect(User.search(user1.username.upcase).to_a).to eq([user1]) - expect(User.search(user1.username.downcase).to_a).to eq([user1]) - expect(User.search(user2.username.upcase).to_a).to eq([user2]) - expect(User.search(user2.username.downcase).to_a).to eq([user2]) - expect(User.search(user1.username.downcase).to_a.size).to eq(2) - expect(User.search(user2.username.downcase).to_a.size).to eq(1) + it 'returns users with a matching username regardless of the casing' do + expect(described_class.search(user.username.upcase)).to eq([user]) end end |