summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2017-10-07 08:07:33 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2017-10-07 08:07:33 +0000
commit5ee20b637553dcb70590edfa30b81d972de37170 (patch)
tree7079e097120fc25438b411c6162a1ae81656c129 /spec/models
parentc0cfc9ebd26583c444f2cce1a23f939bfa7d8969 (diff)
parentd4f3963e98397a0aee4b7a65c76ae404300b41d1 (diff)
downloadgitlab-ce-5ee20b637553dcb70590edfa30b81d972de37170.tar.gz
Merge branch 'master' into '37970-ci-sections-tracking'
# Conflicts: # db/schema.rb
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/ci/artifact_blob_spec.rb50
-rw-r--r--spec/models/ci/pipeline_spec.rb10
-rw-r--r--spec/models/concerns/has_status_spec.rb12
-rw-r--r--spec/models/diff_note_spec.rb40
-rw-r--r--spec/models/email_spec.rb29
-rw-r--r--spec/models/gcp/cluster_spec.rb240
-rw-r--r--spec/models/gpg_key_spec.rb42
-rw-r--r--spec/models/gpg_key_subkey_spec.rb15
-rw-r--r--spec/models/gpg_signature_spec.rb26
-rw-r--r--spec/models/namespace_spec.rb28
-rw-r--r--spec/models/note_spec.rb50
-rw-r--r--spec/models/project_spec.rb15
-rw-r--r--spec/models/repository_spec.rb4
-rw-r--r--spec/models/user_spec.rb206
14 files changed, 721 insertions, 46 deletions
diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb
index a10a8af5303..d5ba088af53 100644
--- a/spec/models/ci/artifact_blob_spec.rb
+++ b/spec/models/ci/artifact_blob_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
describe Ci::ArtifactBlob do
- let(:build) { create(:ci_build, :artifacts) }
+ set(:project) { create(:project, :public) }
+ set(:build) { create(:ci_build, :artifacts, project: project) }
let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/another-subdirectory/banana_sample.gif') }
subject { described_class.new(entry) }
@@ -41,4 +42,51 @@ describe Ci::ArtifactBlob do
expect(subject.external_storage).to eq(:build_artifact)
end
end
+
+ describe '#external_url' do
+ before do
+ allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
+ allow(Gitlab.config.pages).to receive(:artifacts_server).and_return(true)
+ end
+
+ context '.gif extension' do
+ it 'returns nil' do
+ expect(subject.external_url(build.project, build)).to be_nil
+ end
+ end
+
+ context 'txt extensions' do
+ let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/doc_sample.txt') }
+
+ it 'returns a URL' do
+ url = subject.external_url(build.project, build)
+
+ expect(url).not_to be_nil
+ expect(url).to start_with("http")
+ expect(url).to match Gitlab.config.pages.host
+ expect(url).to end_with(entry.path)
+ end
+ end
+ end
+
+ describe '#external_link?' do
+ before do
+ allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
+ allow(Gitlab.config.pages).to receive(:artifacts_server).and_return(true)
+ end
+
+ context 'gif extensions' do
+ it 'returns false' do
+ expect(subject.external_link?(build)).to be false
+ end
+ end
+
+ context 'txt extensions' do
+ let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/doc_sample.txt') }
+
+ it 'returns true' do
+ expect(subject.external_link?(build)).to be true
+ end
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 9c1e460ab20..2c9e7013b77 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -238,7 +238,7 @@ describe Ci::Pipeline, :mailer do
describe '#stage_seeds' do
let(:pipeline) do
- create(:ci_pipeline, config: { rspec: { script: 'rake' } })
+ build(:ci_pipeline, config: { rspec: { script: 'rake' } })
end
it 'returns preseeded stage seeds object' do
@@ -247,6 +247,14 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#seeds_size' do
+ let(:pipeline) { build(:ci_pipeline_with_one_job) }
+
+ it 'returns number of jobs in stage seeds' do
+ expect(pipeline.seeds_size).to eq 1
+ end
+ end
+
describe '#legacy_stages' do
subject { pipeline.legacy_stages }
diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb
index a38f2553eb1..6866b43432c 100644
--- a/spec/models/concerns/has_status_spec.rb
+++ b/spec/models/concerns/has_status_spec.rb
@@ -231,6 +231,18 @@ describe HasStatus do
end
end
+ describe '.alive' do
+ subject { CommitStatus.alive }
+
+ %i[running pending created].each do |status|
+ it_behaves_like 'containing the job', status
+ end
+
+ %i[failed success].each do |status|
+ it_behaves_like 'not containing the job', status
+ end
+ end
+
describe '.created_or_pending' do
subject { CommitStatus.created_or_pending }
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 4aa9ec789a3..eb0a3e9e0d3 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe DiffNote do
include RepoHelpers
- let(:merge_request) { create(:merge_request) }
+ let!(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:commit) { project.commit(sample_commit.id) }
@@ -98,14 +98,14 @@ describe DiffNote do
diff_line = subject.diff_line
expect(diff_line.added?).to be true
- expect(diff_line.new_line).to eq(position.new_line)
+ expect(diff_line.new_line).to eq(position.formatter.new_line)
expect(diff_line.text).to eq("+ vars = {")
end
end
describe "#line_code" do
it "returns the correct line code" do
- line_code = Gitlab::Diff::LineCode.generate(position.file_path, position.new_line, 15)
+ line_code = Gitlab::Diff::LineCode.generate(position.file_path, position.formatter.new_line, 15)
expect(subject.line_code).to eq(line_code)
end
@@ -255,4 +255,38 @@ describe DiffNote do
end
end
end
+
+ describe "image diff notes" do
+ let(:path) { "files/images/any_image.png" }
+
+ let!(:position) do
+ Gitlab::Diff::Position.new(
+ old_path: path,
+ new_path: path,
+ width: 10,
+ height: 10,
+ x: 1,
+ y: 1,
+ diff_refs: merge_request.diff_refs,
+ position_type: "image"
+ )
+ end
+
+ describe "validations" do
+ subject { build(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request) }
+
+ it { is_expected.not_to validate_presence_of(:line_code) }
+
+ it "does not validate diff line" do
+ diff_line = subject.diff_line
+
+ expect(diff_line).to be nil
+ expect(subject).to be_valid
+ end
+ end
+
+ it "returns true for on_image?" do
+ expect(subject.on_image?).to be_truthy
+ end
+ end
end
diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb
index 1d6fabe48b1..b32dd31ae6d 100644
--- a/spec/models/email_spec.rb
+++ b/spec/models/email_spec.rb
@@ -11,4 +11,33 @@ describe Email do
expect(described_class.new(email: ' inFO@exAMPLe.com ').email)
.to eq 'info@example.com'
end
+
+ describe '#update_invalid_gpg_signatures' do
+ let(:user) do
+ create(:user, email: 'tula.torphy@abshire.ca').tap do |user|
+ user.skip_reconfirmation!
+ end
+ end
+ let(:user) { create(:user) }
+
+ it 'synchronizes the gpg keys when the email is updated' do
+ email = user.emails.create(email: 'new@email.com')
+
+ expect(user).to receive(:update_invalid_gpg_signatures)
+
+ email.confirm
+ end
+ end
+
+ describe 'scopes' do
+ let(:user) { create(:user) }
+
+ it 'scopes confirmed emails' do
+ create(:email, :confirmed, user: user)
+ create(:email, user: user)
+
+ expect(user.emails.count).to eq 2
+ expect(user.emails.confirmed.count).to eq 1
+ end
+ end
end
diff --git a/spec/models/gcp/cluster_spec.rb b/spec/models/gcp/cluster_spec.rb
new file mode 100644
index 00000000000..350fbc257d9
--- /dev/null
+++ b/spec/models/gcp/cluster_spec.rb
@@ -0,0 +1,240 @@
+require 'spec_helper'
+
+describe Gcp::Cluster do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:service) }
+
+ it { is_expected.to validate_presence_of(:gcp_cluster_zone) }
+
+ describe '#default_value_for' do
+ let(:cluster) { described_class.new }
+
+ it { expect(cluster.gcp_cluster_zone).to eq('us-central1-a') }
+ it { expect(cluster.gcp_cluster_size).to eq(3) }
+ it { expect(cluster.gcp_machine_type).to eq('n1-standard-4') }
+ end
+
+ describe '#validates' do
+ subject { cluster.valid? }
+
+ context 'when validates gcp_project_id' do
+ let(:cluster) { build(:gcp_cluster, gcp_project_id: gcp_project_id) }
+
+ context 'when valid' do
+ let(:gcp_project_id) { 'gcp-project-12345' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when empty' do
+ let(:gcp_project_id) { '' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when too long' do
+ let(:gcp_project_id) { 'A' * 64 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when includes abnormal character' do
+ let(:gcp_project_id) { '!!!!!!' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when validates gcp_cluster_name' do
+ let(:cluster) { build(:gcp_cluster, gcp_cluster_name: gcp_cluster_name) }
+
+ context 'when valid' do
+ let(:gcp_cluster_name) { 'test-cluster' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when empty' do
+ let(:gcp_cluster_name) { '' }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when too long' do
+ let(:gcp_cluster_name) { 'A' * 64 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when includes abnormal character' do
+ let(:gcp_cluster_name) { '!!!!!!' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when validates gcp_cluster_size' do
+ let(:cluster) { build(:gcp_cluster, gcp_cluster_size: gcp_cluster_size) }
+
+ context 'when valid' do
+ let(:gcp_cluster_size) { 1 }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when zero' do
+ let(:gcp_cluster_size) { 0 }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when validates project_namespace' do
+ let(:cluster) { build(:gcp_cluster, project_namespace: project_namespace) }
+
+ context 'when valid' do
+ let(:project_namespace) { 'default-namespace' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when empty' do
+ let(:project_namespace) { '' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when too long' do
+ let(:project_namespace) { 'A' * 64 }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when includes abnormal character' do
+ let(:project_namespace) { '!!!!!!' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when validates restrict_modification' do
+ let(:cluster) { create(:gcp_cluster) }
+
+ before do
+ cluster.make_creating!
+ end
+
+ context 'when created' do
+ before do
+ cluster.make_created!
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when creating' do
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ describe '#state_machine' do
+ let(:cluster) { build(:gcp_cluster) }
+
+ context 'when transits to created state' do
+ before do
+ cluster.gcp_token = 'tmp'
+ cluster.gcp_operation_id = 'tmp'
+ cluster.make_created!
+ end
+
+ it 'nullify gcp_token and gcp_operation_id' do
+ expect(cluster.gcp_token).to be_nil
+ expect(cluster.gcp_operation_id).to be_nil
+ expect(cluster).to be_created
+ end
+ end
+
+ context 'when transits to errored state' do
+ let(:reason) { 'something wrong' }
+
+ before do
+ cluster.make_errored!(reason)
+ end
+
+ it 'sets status_reason' do
+ expect(cluster.status_reason).to eq(reason)
+ expect(cluster).to be_errored
+ end
+ end
+ end
+
+ describe '#project_namespace_placeholder' do
+ subject { cluster.project_namespace_placeholder }
+
+ let(:cluster) { create(:gcp_cluster) }
+
+ it 'returns a placeholder' do
+ is_expected.to eq("#{cluster.project.path}-#{cluster.project.id}")
+ end
+ end
+
+ describe '#on_creation?' do
+ subject { cluster.on_creation? }
+
+ let(:cluster) { create(:gcp_cluster) }
+
+ context 'when status is creating' do
+ before do
+ cluster.make_creating!
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when status is created' do
+ before do
+ cluster.make_created!
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#api_url' do
+ subject { cluster.api_url }
+
+ let(:cluster) { create(:gcp_cluster, :created_on_gke) }
+ let(:api_url) { 'https://' + cluster.endpoint }
+
+ it { is_expected.to eq(api_url) }
+ end
+
+ describe '#restrict_modification' do
+ subject { cluster.restrict_modification }
+
+ let(:cluster) { create(:gcp_cluster) }
+
+ context 'when status is created' do
+ before do
+ cluster.make_created!
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when status is creating' do
+ before do
+ cluster.make_creating!
+ end
+
+ it { is_expected.to be_falsey }
+
+ it 'sets error' do
+ is_expected.to be_falsey
+ expect(cluster.errors).not_to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
index 4a4d079b721..33e6f1de3d1 100644
--- a/spec/models/gpg_key_spec.rb
+++ b/spec/models/gpg_key_spec.rb
@@ -3,6 +3,7 @@ require 'rails_helper'
describe GpgKey do
describe "associations" do
it { is_expected.to belong_to(:user) }
+ it { is_expected.to have_many(:subkeys) }
end
describe "validation" do
@@ -38,6 +39,14 @@ describe GpgKey do
expect(gpg_key.primary_keyid).to eq GpgHelpers::User1.primary_keyid
end
end
+
+ describe 'generate_subkeys' do
+ it 'extracts the subkeys from the gpg key' do
+ gpg_key = create(:gpg_key, key: GpgHelpers::User1.public_key_with_extra_signing_key)
+
+ expect(gpg_key.subkeys.count).to eq(2)
+ end
+ end
end
describe '#key=' do
@@ -90,11 +99,20 @@ describe GpgKey do
it 'email is verified if the user has the matching email' do
user = create :user, email: 'bette.cartwright@example.com'
gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user
+ create :email, user: user
+ user.reload
expect(gpg_key.emails_with_verified_status).to eq(
'bette.cartwright@example.com' => true,
'bette.cartwright@example.net' => false
)
+
+ create :email, :confirmed, user: user, email: 'bette.cartwright@example.net'
+ user.reload
+ expect(gpg_key.emails_with_verified_status).to eq(
+ 'bette.cartwright@example.com' => true,
+ 'bette.cartwright@example.net' => true
+ )
end
end
@@ -173,5 +191,29 @@ describe GpgKey do
expect(unrelated_gpg_key.destroyed?).to be false
end
+
+ it 'deletes all the associated subkeys' do
+ gpg_key = create :gpg_key, key: GpgHelpers::User3.public_key
+
+ expect(gpg_key.subkeys).to be_present
+
+ gpg_key.revoke
+
+ expect(gpg_key.subkeys(true)).to be_blank
+ end
+
+ it 'invalidates all signatures associated to the subkeys' do
+ gpg_key = create :gpg_key, key: GpgHelpers::User3.public_key
+ gpg_key_subkey = gpg_key.subkeys.last
+ gpg_signature = create :gpg_signature, verification_status: :verified, gpg_key: gpg_key_subkey
+
+ gpg_key.revoke
+
+ expect(gpg_signature.reload).to have_attributes(
+ verification_status: 'unknown_key',
+ gpg_key: nil,
+ gpg_key_subkey: nil
+ )
+ end
end
end
diff --git a/spec/models/gpg_key_subkey_spec.rb b/spec/models/gpg_key_subkey_spec.rb
new file mode 100644
index 00000000000..3c86837f47f
--- /dev/null
+++ b/spec/models/gpg_key_subkey_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+describe GpgKeySubkey do
+ subject { build(:gpg_key_subkey) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:gpg_key) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:gpg_key_id) }
+ it { is_expected.to validate_presence_of(:fingerprint) }
+ it { is_expected.to validate_presence_of(:keyid) }
+ end
+end
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index c58fd46762a..db033016c37 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -1,9 +1,13 @@
require 'rails_helper'
RSpec.describe GpgSignature do
+ let(:gpg_key) { create(:gpg_key) }
+ let(:gpg_key_subkey) { create(:gpg_key_subkey) }
+
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:gpg_key) }
+ it { is_expected.to belong_to(:gpg_key_subkey) }
end
describe 'validation' do
@@ -25,4 +29,26 @@ RSpec.describe GpgSignature do
gpg_signature.commit
end
end
+
+ describe '#gpg_key=' do
+ it 'supports the assignment of a GpgKey' do
+ gpg_signature = create(:gpg_signature, gpg_key: gpg_key)
+
+ expect(gpg_signature.gpg_key).to be_an_instance_of(GpgKey)
+ end
+
+ it 'supports the assignment of a GpgKeySubkey' do
+ gpg_signature = create(:gpg_signature, gpg_key: gpg_key_subkey)
+
+ expect(gpg_signature.gpg_key).to be_an_instance_of(GpgKeySubkey)
+ end
+
+ it 'clears gpg_key and gpg_key_subkey_id when passing nil' do
+ gpg_signature = create(:gpg_signature, gpg_key: gpg_key_subkey)
+ gpg_signature.update_attribute(:gpg_key, nil)
+
+ expect(gpg_signature.gpg_key_id).to be_nil
+ expect(gpg_signature.gpg_key_subkey_id).to be_nil
+ end
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 81d5ab7a6d3..3ea614776ca 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -152,22 +152,24 @@ describe Namespace do
end
describe '#move_dir' do
+ let(:namespace) { create(:namespace) }
+ let!(:project) { create(:project_empty_repo, namespace: namespace) }
+
before do
- @namespace = create :namespace
- @project = create(:project_empty_repo, namespace: @namespace)
- allow(@namespace).to receive(:path_changed?).and_return(true)
+ allow(namespace).to receive(:path_changed?).and_return(true)
end
it "raises error when directory exists" do
- expect { @namespace.move_dir }.to raise_error("namespace directory cannot be moved")
+ expect { namespace.move_dir }.to raise_error("namespace directory cannot be moved")
end
it "moves dir if path changed" do
- new_path = @namespace.full_path + "_new"
- allow(@namespace).to receive(:full_path_was).and_return(@namespace.full_path)
- allow(@namespace).to receive(:full_path).and_return(new_path)
- expect(@namespace).to receive(:remove_exports!)
- expect(@namespace.move_dir).to be_truthy
+ new_path = namespace.full_path + "_new"
+
+ allow(namespace).to receive(:full_path_was).and_return(namespace.full_path)
+ allow(namespace).to receive(:full_path).and_return(new_path)
+ expect(namespace).to receive(:remove_exports!)
+ expect(namespace.move_dir).to be_truthy
end
context "when any project has container images" do
@@ -177,14 +179,14 @@ describe Namespace do
stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: ['tag'])
- create(:project, namespace: @namespace, container_repositories: [container_repository])
+ create(:project, namespace: namespace, container_repositories: [container_repository])
- allow(@namespace).to receive(:path_was).and_return(@namespace.path)
- allow(@namespace).to receive(:path).and_return('new_path')
+ allow(namespace).to receive(:path_was).and_return(namespace.path)
+ allow(namespace).to receive(:path).and_return('new_path')
end
it 'raises an error about not movable project' do
- expect { @namespace.move_dir }.to raise_error(/Namespace cannot be moved/)
+ expect { namespace.move_dir }.to raise_error(/Namespace cannot be moved/)
end
end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index b214074fdce..1ecb50586c7 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -314,6 +314,56 @@ describe Note do
expect(subject[active_diff_note1.line_code].first.id).to eq(active_diff_note1.discussion_id)
expect(subject[active_diff_note3.line_code].first.id).to eq(active_diff_note3.discussion_id)
end
+
+ context 'with image discussions' do
+ let(:merge_request2) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, title: "Added images and changes") }
+ let(:image_path) { "files/images/ee_repo_logo.png" }
+ let(:text_path) { "bar/branch-test.txt" }
+ let!(:image_note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request2, position: image_position) }
+ let!(:text_note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request2, position: text_position) }
+
+ let(:image_position) do
+ Gitlab::Diff::Position.new(
+ old_path: image_path,
+ new_path: image_path,
+ width: 100,
+ height: 100,
+ x: 1,
+ y: 1,
+ position_type: "image",
+ diff_refs: merge_request2.diff_refs
+ )
+ end
+
+ let(:text_position) do
+ Gitlab::Diff::Position.new(
+ old_path: text_path,
+ new_path: text_path,
+ old_line: nil,
+ new_line: 2,
+ position_type: "text",
+ diff_refs: merge_request2.diff_refs
+ )
+ end
+
+ it "groups image discussions by file identifier" do
+ diff_discussion = DiffDiscussion.new([image_note])
+
+ discussions = merge_request2.notes.grouped_diff_discussions
+
+ expect(discussions.size).to eq(2)
+ expect(discussions[image_note.diff_file.new_path]).to include(diff_discussion)
+ end
+
+ it "groups text discussions by line code" do
+ diff_discussion = DiffDiscussion.new([text_note])
+
+ discussions = merge_request2.notes.grouped_diff_discussions
+
+ expect(discussions.size).to eq(2)
+ expect(discussions[text_note.line_code]).to include(diff_discussion)
+ end
+ end
end
context 'diff discussions for older diff refs' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 1c04cb8cb5f..760ea7da322 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -77,6 +77,7 @@ describe Project do
it { is_expected.to have_many(:uploads).dependent(:destroy) }
it { is_expected.to have_many(:pipeline_schedules) }
it { is_expected.to have_many(:members_and_requesters) }
+ it { is_expected.to have_one(:cluster) }
context 'after initialized' do
it "has a project_feature" do
@@ -422,20 +423,10 @@ describe Project do
end
describe '#repository_storage_path' do
- let(:project) { create(:project, repository_storage: 'custom') }
-
- before do
- FileUtils.mkdir('tmp/tests/custom_repositories')
- storages = { 'custom' => { 'path' => 'tmp/tests/custom_repositories' } }
- allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
- end
-
- after do
- FileUtils.rm_rf('tmp/tests/custom_repositories')
- end
+ let(:project) { create(:project) }
it 'returns the repository storage path' do
- expect(project.repository_storage_path).to eq('tmp/tests/custom_repositories')
+ expect(Dir.exist?(project.repository_storage_path)).to be(true)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 7156c1b7aa8..5764c451b67 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -634,6 +634,10 @@ describe Repository do
end
describe '#fetch_ref' do
+ # Setting the var here, sidesteps the stub that makes gitaly raise an error
+ # before the actual test call
+ set(:broken_repository) { create(:project, :broken_storage).repository }
+
describe 'when storage is broken', broken_storage: true do
it 'should raise a storage error' do
expect_to_raise_storage_error do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 62890dd5002..995211845ce 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -360,9 +360,22 @@ describe User do
expect(external_user.projects_limit).to be 0
end
end
+
+ describe '#check_for_verified_email' do
+ let(:user) { create(:user) }
+ let(:secondary) { create(:email, :confirmed, email: 'secondary@example.com', user: user) }
+
+ it 'allows a verfied secondary email to be used as the primary without needing reconfirmation' do
+ user.update_attributes!(email: secondary.email)
+ user.reload
+ expect(user.email).to eq secondary.email
+ expect(user.unconfirmed_email).to eq nil
+ expect(user.confirmed?).to be_truthy
+ end
+ end
end
- describe 'after update hook' do
+ describe 'after commit hook' do
describe '.update_invalid_gpg_signatures' do
let(:user) do
create(:user, email: 'tula.torphy@abshire.ca').tap do |user|
@@ -376,10 +389,50 @@ describe User do
end
it 'synchronizes the gpg keys when the email is updated' do
- expect(user).to receive(:update_invalid_gpg_signatures)
+ expect(user).to receive(:update_invalid_gpg_signatures).at_most(:twice)
user.update_attributes!(email: 'shawnee.ritchie@denesik.com')
end
end
+
+ describe '#update_emails_with_primary_email' do
+ before do
+ @user = create(:user, email: 'primary@example.com').tap do |user|
+ user.skip_reconfirmation!
+ end
+ @secondary = create :email, email: 'secondary@example.com', user: @user
+ @user.reload
+ end
+
+ it 'gets called when email updated' do
+ expect(@user).to receive(:update_emails_with_primary_email)
+
+ @user.update_attributes!(email: 'new_primary@example.com')
+ end
+
+ it 'adds old primary to secondary emails when secondary is a new email ' do
+ @user.update_attributes!(email: 'new_primary@example.com')
+ @user.reload
+
+ expect(@user.emails.count).to eq 2
+ expect(@user.emails.pluck(:email)).to match_array([@secondary.email, 'primary@example.com'])
+ end
+
+ it 'adds old primary to secondary emails if secondary is becoming a primary' do
+ @user.update_attributes!(email: @secondary.email)
+ @user.reload
+
+ expect(@user.emails.count).to eq 1
+ expect(@user.emails.first.email).to eq 'primary@example.com'
+ end
+
+ it 'transfers old confirmation values into new secondary' do
+ @user.update_attributes!(email: @secondary.email)
+ @user.reload
+
+ expect(@user.emails.count).to eq 1
+ expect(@user.emails.first.confirmed_at).not_to eq nil
+ end
+ end
end
describe '#update_tracked_fields!', :clean_gitlab_redis_shared_state do
@@ -467,6 +520,7 @@ describe User do
describe '#generate_password' do
it "does not generate password by default" do
user = create(:user, password: 'abcdefghe')
+
expect(user.password).to eq('abcdefghe')
end
end
@@ -474,6 +528,7 @@ describe User do
describe 'authentication token' do
it "has authentication token" do
user = create(:user)
+
expect(user.authentication_token).not_to be_blank
end
end
@@ -481,6 +536,7 @@ describe User do
describe 'ensure incoming email token' do
it 'has incoming email token' do
user = create(:user)
+
expect(user.incoming_email_token).not_to be_blank
end
end
@@ -523,6 +579,7 @@ describe User do
it 'ensures an rss token on read' do
user = create(:user, rss_token: nil)
rss_token = user.rss_token
+
expect(rss_token).not_to be_blank
expect(user.reload.rss_token).to eq rss_token
end
@@ -633,6 +690,7 @@ describe User do
it "blocks user" do
user.block
+
expect(user.blocked?).to be_truthy
end
end
@@ -966,6 +1024,7 @@ describe User do
it 'is case-insensitive' do
user = create(:user, username: 'JohnDoe')
+
expect(described_class.find_by_username('JOHNDOE')).to eq user
end
end
@@ -978,6 +1037,7 @@ describe User do
it 'is case-insensitive' do
user = create(:user, username: 'JohnDoe')
+
expect(described_class.find_by_username!('JOHNDOE')).to eq user
end
end
@@ -1067,11 +1127,13 @@ describe User 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
user.update_attribute(:avatar, 'uploads/avatar.html')
+
expect(user.avatar_type).to eq(['only images allowed'])
end
end
@@ -1094,6 +1156,50 @@ describe User do
end
end
+ describe '#all_emails' do
+ let(:user) { create(:user) }
+
+ it 'returns all emails' do
+ email_confirmed = create :email, user: user, confirmed_at: Time.now
+ email_unconfirmed = create :email, user: user
+ user.reload
+
+ expect(user.all_emails).to match_array([user.email, email_unconfirmed.email, email_confirmed.email])
+ end
+ end
+
+ describe '#verified_emails' do
+ let(:user) { create(:user) }
+
+ it 'returns only confirmed emails' do
+ email_confirmed = create :email, user: user, confirmed_at: Time.now
+ create :email, user: user
+ user.reload
+
+ expect(user.verified_emails).to match_array([user.email, email_confirmed.email])
+ end
+ end
+
+ describe '#verified_email?' do
+ let(:user) { create(:user) }
+
+ it 'returns true when the email is verified/confirmed' do
+ email_confirmed = create :email, user: user, confirmed_at: Time.now
+ create :email, user: user
+ user.reload
+
+ expect(user.verified_email?(user.email)).to be_truthy
+ expect(user.verified_email?(email_confirmed.email.titlecase)).to be_truthy
+ end
+
+ it 'returns false when the email is not verified/confirmed' do
+ email_unconfirmed = create :email, user: user
+ user.reload
+
+ expect(user.verified_email?(email_unconfirmed.email)).to be_falsy
+ end
+ end
+
describe '#requires_ldap_check?' do
let(:user) { described_class.new }
@@ -1101,6 +1207,7 @@ describe User do
# Create a condition which would otherwise cause 'true' to be returned
allow(user).to receive(:ldap_user?).and_return(true)
user.last_credential_check_at = nil
+
expect(user.requires_ldap_check?).to be_falsey
end
@@ -1111,6 +1218,7 @@ describe User do
it 'is false for non-LDAP users' do
allow(user).to receive(:ldap_user?).and_return(false)
+
expect(user.requires_ldap_check?).to be_falsey
end
@@ -1121,11 +1229,13 @@ describe User do
it 'is true when the user has never had an LDAP check before' do
user.last_credential_check_at = nil
+
expect(user.requires_ldap_check?).to be_truthy
end
it 'is true when the last LDAP check happened over 1 hour ago' do
user.last_credential_check_at = 2.hours.ago
+
expect(user.requires_ldap_check?).to be_truthy
end
end
@@ -1136,16 +1246,19 @@ describe User do
describe '#ldap_user?' do
it 'is true if provider name starts with ldap' do
user = create(:omniauth_user, provider: 'ldapmain')
+
expect(user.ldap_user?).to be_truthy
end
it 'is false for other providers' do
user = create(:omniauth_user, provider: 'other-provider')
+
expect(user.ldap_user?).to be_falsey
end
it 'is false if no extern_uid is provided' do
user = create(:omniauth_user, extern_uid: nil)
+
expect(user.ldap_user?).to be_falsey
end
end
@@ -1153,6 +1266,7 @@ describe User do
describe '#ldap_identity' do
it 'returns ldap identity' do
user = create :omniauth_user
+
expect(user.ldap_identity.provider).not_to be_empty
end
end
@@ -1162,6 +1276,7 @@ describe User do
it 'blocks user flaging the action caming from ldap' do
user.ldap_block
+
expect(user.blocked?).to be_truthy
expect(user.ldap_blocked?).to be_truthy
end
@@ -1234,18 +1349,22 @@ describe User do
expect(user.starred?(project2)).to be_falsey
star1 = UsersStarProject.create!(project: project1, user: user)
+
expect(user.starred?(project1)).to be_truthy
expect(user.starred?(project2)).to be_falsey
star2 = UsersStarProject.create!(project: project2, user: user)
+
expect(user.starred?(project1)).to be_truthy
expect(user.starred?(project2)).to be_truthy
star1.destroy
+
expect(user.starred?(project1)).to be_falsey
expect(user.starred?(project2)).to be_truthy
star2.destroy
+
expect(user.starred?(project1)).to be_falsey
expect(user.starred?(project2)).to be_falsey
end
@@ -1257,9 +1376,13 @@ describe User do
project = create(:project, :public)
expect(user.starred?(project)).to be_falsey
+
user.toggle_star(project)
+
expect(user.starred?(project)).to be_truthy
+
user.toggle_star(project)
+
expect(user.starred?(project)).to be_falsey
end
end
@@ -1438,9 +1561,11 @@ describe User do
user = create(:user)
member = group.add_developer(user)
+
expect(user.authorized_projects).to include(project)
member.destroy
+
expect(user.authorized_projects).not_to include(project)
end
@@ -1461,9 +1586,11 @@ describe User do
project = create(:project, :private, namespace: user1.namespace)
project.team << [user2, Gitlab::Access::DEVELOPER]
+
expect(user2.authorized_projects).to include(project)
project.destroy
+
expect(user2.authorized_projects).not_to include(project)
end
@@ -1473,9 +1600,11 @@ describe User do
user = create(:user)
group.add_developer(user)
+
expect(user.authorized_projects).to include(project)
group.destroy
+
expect(user.authorized_projects).not_to include(project)
end
end
@@ -2019,7 +2148,9 @@ describe User do
it 'creates the namespace' do
expect(user.namespace).to be_nil
+
user.save!
+
expect(user.namespace).not_to be_nil
end
end
@@ -2040,11 +2171,13 @@ describe User do
it 'updates the namespace name' do
user.update_attributes!(username: new_username)
+
expect(user.namespace.name).to eq(new_username)
end
it 'updates the namespace path' do
user.update_attributes!(username: new_username)
+
expect(user.namespace.path).to eq(new_username)
end
@@ -2058,6 +2191,7 @@ describe User do
it 'adds the namespace errors to the user' do
user.update_attributes(username: new_username)
+
expect(user.errors.full_messages.first).to eq('Namespace name has already been taken')
end
end
@@ -2074,56 +2208,49 @@ describe User do
end
end
- describe '#verified_email?' do
- it 'returns true when the email is the primary email' do
- user = build :user, email: 'email@example.com'
-
- expect(user.verified_email?('email@example.com')).to be true
- end
-
- it 'returns false when the email is not the primary email' do
- user = build :user, email: 'email@example.com'
-
- expect(user.verified_email?('other_email@example.com')).to be false
- end
- end
-
describe '#sync_attribute?' do
let(:user) { described_class.new }
context 'oauth user' do
it 'returns true if name can be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(name location))
+
expect(user.sync_attribute?(:name)).to be_truthy
end
it 'returns true if email can be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(name email))
+
expect(user.sync_attribute?(:email)).to be_truthy
end
it 'returns true if location can be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(location email))
+
expect(user.sync_attribute?(:email)).to be_truthy
end
it 'returns false if name can not be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(location email))
+
expect(user.sync_attribute?(:name)).to be_falsey
end
it 'returns false if email can not be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(location email))
+
expect(user.sync_attribute?(:name)).to be_falsey
end
it 'returns false if location can not be synced' do
stub_omniauth_setting(sync_profile_attributes: %w(location email))
+
expect(user.sync_attribute?(:name)).to be_falsey
end
it 'returns true for all syncable attributes if all syncable attributes can be synced' do
stub_omniauth_setting(sync_profile_attributes: true)
+
expect(user.sync_attribute?(:name)).to be_truthy
expect(user.sync_attribute?(:email)).to be_truthy
expect(user.sync_attribute?(:location)).to be_truthy
@@ -2139,6 +2266,7 @@ describe User do
context 'ldap user' do
it 'returns true for email if ldap user' do
allow(user).to receive(:ldap_user?).and_return(true)
+
expect(user.sync_attribute?(:name)).to be_falsey
expect(user.sync_attribute?(:email)).to be_truthy
expect(user.sync_attribute?(:location)).to be_falsey
@@ -2147,10 +2275,56 @@ describe User do
it 'returns true for email and location if ldap user and location declared as syncable' do
allow(user).to receive(:ldap_user?).and_return(true)
stub_omniauth_setting(sync_profile_attributes: %w(location))
+
expect(user.sync_attribute?(:name)).to be_falsey
expect(user.sync_attribute?(:email)).to be_truthy
expect(user.sync_attribute?(:location)).to be_truthy
end
end
end
+
+ describe '#confirm_deletion_with_password?' do
+ where(
+ password_automatically_set: [true, false],
+ ldap_user: [true, false],
+ password_authentication_disabled: [true, false]
+ )
+
+ with_them do
+ let!(:user) { create(:user, password_automatically_set: password_automatically_set) }
+ let!(:identity) { create(:identity, user: user) if ldap_user }
+
+ # Only confirm deletion with password if all inputs are false
+ let(:expected) { !(password_automatically_set || ldap_user || password_authentication_disabled) }
+
+ before do
+ stub_application_setting(password_authentication_enabled: !password_authentication_disabled)
+ end
+
+ it 'returns false unless all inputs are true' do
+ expect(user.confirm_deletion_with_password?).to eq(expected)
+ end
+ end
+ end
+
+ describe '#delete_async' do
+ let(:user) { create(:user) }
+ let(:deleted_by) { create(:user) }
+
+ it 'blocks the user then schedules them for deletion if a hard delete is specified' do
+ expect(DeleteUserWorker).to receive(:perform_async).with(deleted_by.id, user.id, hard_delete: true)
+
+ user.delete_async(deleted_by: deleted_by, params: { hard_delete: true })
+
+ expect(user).to be_blocked
+ end
+
+ it 'schedules user for deletion without blocking them' do
+ expect(DeleteUserWorker).to receive(:perform_async).with(deleted_by.id, user.id, {})
+
+ user.delete_async(deleted_by: deleted_by)
+
+ expect(user).not_to be_blocked
+ end
+ end
end