summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
authorFelipe Artur <felipefac@gmail.com>2016-03-16 20:16:42 -0300
committerFelipe Artur <felipefac@gmail.com>2016-03-16 20:16:42 -0300
commit44c127447b5a3cfc7aaea6f19e18baf9f42ad500 (patch)
treef386dbb06fec8c5fdec92812394ac63cf67183a0 /spec/models
parentec20fdf366843e60ed30abb5322c3c1b8f471b4a (diff)
parent59064aeeef8562a87d4d03efa9b11012a007e261 (diff)
downloadgitlab-ce-44c127447b5a3cfc7aaea6f19e18baf9f42ad500.tar.gz
Merge 4009-external-users into issue_12658
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/build_spec.rb66
-rw-r--r--spec/models/ci/commit_spec.rb44
-rw-r--r--spec/models/ci/runner_spec.rb28
-rw-r--r--spec/models/concerns/issuable_spec.rb89
-rw-r--r--spec/models/concerns/subscribable_spec.rb57
-rw-r--r--spec/models/group_spec.rb26
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb6
-rw-r--r--spec/models/milestone_spec.rb30
-rw-r--r--spec/models/namespace_spec.rb29
-rw-r--r--spec/models/note_spec.rb82
-rw-r--r--spec/models/project_group_link_spec.rb17
-rw-r--r--spec/models/project_spec.rb96
-rw-r--r--spec/models/project_team_spec.rb44
-rw-r--r--spec/models/snippet_spec.rb44
-rw-r--r--spec/models/user_spec.rb87
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