summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/application_record_spec.rb23
-rw-r--r--spec/models/application_setting_spec.rb7
-rw-r--r--spec/models/ci/build_spec.rb20
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb16
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb15
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb15
-rw-r--r--spec/models/clusters/applications/knative_spec.rb15
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb15
-rw-r--r--spec/models/clusters/applications/runner_spec.rb15
-rw-r--r--spec/models/commit_collection_spec.rb11
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb233
-rw-r--r--spec/models/concerns/issuable_spec.rb72
-rw-r--r--spec/models/environment_spec.rb70
-rw-r--r--spec/models/gpg_signature_spec.rb35
-rw-r--r--spec/models/merge_request_diff_spec.rb189
-rw-r--r--spec/models/merge_request_spec.rb48
-rw-r--r--spec/models/project_spec.rb8
-rw-r--r--spec/models/project_wiki_spec.rb4
-rw-r--r--spec/models/repository_spec.rb2
-rw-r--r--spec/models/resource_label_event_spec.rb6
-rw-r--r--spec/models/sent_notification_spec.rb34
-rw-r--r--spec/models/ssh_host_key_spec.rb23
22 files changed, 564 insertions, 312 deletions
diff --git a/spec/models/application_record_spec.rb b/spec/models/application_record_spec.rb
index 68aed387bfc..fd25132ed3a 100644
--- a/spec/models/application_record_spec.rb
+++ b/spec/models/application_record_spec.rb
@@ -10,4 +10,27 @@ describe ApplicationRecord do
expect(User.id_in(records.last(2).map(&:id))).to eq(records.last(2))
end
end
+
+ describe '.safe_find_or_create_by' do
+ it 'creates the user avoiding race conditions' do
+ expect(Suggestion).to receive(:find_or_create_by).and_raise(ActiveRecord::RecordNotUnique)
+ allow(Suggestion).to receive(:find_or_create_by).and_call_original
+
+ expect { Suggestion.safe_find_or_create_by(build(:suggestion).attributes) }
+ .to change { Suggestion.count }.by(1)
+ end
+ end
+
+ describe '.safe_find_or_create_by!' do
+ it 'creates a record using safe_find_or_create_by' do
+ expect(Suggestion).to receive(:find_or_create_by).and_call_original
+
+ expect(Suggestion.safe_find_or_create_by!(build(:suggestion).attributes))
+ .to be_a(Suggestion)
+ end
+
+ it 'raises a validation error if the record was not persisted' do
+ expect { Suggestion.find_or_create_by!(note: nil) }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+ end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 96aa9a82b71..789e14e8a20 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -70,6 +70,13 @@ describe ApplicationSetting do
.is_greater_than(0)
end
+ it do
+ is_expected.to validate_numericality_of(:local_markdown_version)
+ .only_integer
+ .is_greater_than_or_equal_to(0)
+ .is_less_than(65536)
+ end
+
context 'key restrictions' do
it 'supports all key types' do
expect(described_class::SUPPORTED_KEY_TYPES).to contain_exactly(:rsa, :dsa, :ecdsa, :ed25519)
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 8a1bbb26e57..47865e4d08f 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1844,6 +1844,26 @@ describe Ci::Build do
context 'when there is no environment' do
it { is_expected.to be_nil }
end
+
+ context 'when build has a start environment' do
+ let(:build) { create(:ci_build, :deploy_to_production, pipeline: pipeline) }
+
+ it 'does not expand environment name' do
+ expect(build).not_to receive(:expanded_environment_name)
+
+ subject
+ end
+ end
+
+ context 'when build has a stop environment' do
+ let(:build) { create(:ci_build, :stop_review_app, pipeline: pipeline) }
+
+ it 'expands environment name' do
+ expect(build).to receive(:expanded_environment_name)
+
+ subject
+ end
+ end
end
describe '#play' do
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index 8e14abe098d..79a06c35459 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -4,20 +4,8 @@ describe Clusters::Applications::CertManager do
let(:cert_manager) { create(:clusters_applications_cert_managers) }
include_examples 'cluster application core specs', :clusters_applications_cert_managers
-
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_cert_managers, :scheduled, version: 'v0.4.0') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('v0.5.2')
- end
- end
- end
+ include_examples 'cluster application status specs', :clusters_applications_cert_managers
+ include_examples 'cluster application initial status specs'
describe '#install_command' do
let(:cluster_issuer_file) { { "cluster_issuer.yaml": "---\napiVersion: certmanager.k8s.io/v1alpha1\nkind: ClusterIssuer\nmetadata:\n name: letsencrypt-prod\nspec:\n acme:\n server: https://acme-v02.api.letsencrypt.org/directory\n email: admin@example.com\n privateKeySecretRef:\n name: letsencrypt-prod\n http01: {}\n" } }
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index 52c347229c6..6d48131d1cc 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -8,6 +8,7 @@ describe Clusters::Applications::Ingress do
include_examples 'cluster application core specs', :clusters_applications_ingress
include_examples 'cluster application status specs', :clusters_applications_ingress
include_examples 'cluster application helm specs', :clusters_applications_ingress
+ include_examples 'cluster application initial status specs'
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
@@ -26,20 +27,6 @@ describe Clusters::Applications::Ingress do
it { is_expected.to contain_exactly(cluster) }
end
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_ingress, :scheduled, version: '0.22.0') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('1.1.2')
- end
- end
- end
-
describe '#make_installed!' do
before do
application.make_installed!
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index 391e5425384..b73a243f6e0 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
describe Clusters::Applications::Jupyter do
include_examples 'cluster application core specs', :clusters_applications_jupyter
+ include_examples 'cluster application status specs', :clusters_applications_jupyter
include_examples 'cluster application helm specs', :clusters_applications_jupyter
it { is_expected.to belong_to(:oauth_application) }
@@ -26,20 +27,6 @@ describe Clusters::Applications::Jupyter do
end
end
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_jupyter, :scheduled, version: 'v0.5') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('v0.6')
- end
- end
- end
-
describe '#install_command' do
let!(:ingress) { create(:clusters_applications_ingress, :installed, external_ip: '127.0.0.1') }
let!(:jupyter) { create(:clusters_applications_jupyter, cluster: ingress.cluster) }
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index 35818be8deb..5519615d52d 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -9,6 +9,7 @@ describe Clusters::Applications::Knative do
include_examples 'cluster application core specs', :clusters_applications_knative
include_examples 'cluster application status specs', :clusters_applications_knative
include_examples 'cluster application helm specs', :clusters_applications_knative
+ include_examples 'cluster application initial status specs'
before do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in)
@@ -34,20 +35,6 @@ describe Clusters::Applications::Knative do
it { is_expected.to contain_exactly(cluster) }
end
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_knative, :scheduled, version: '0.2.2') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('0.2.2')
- end
- end
- end
-
describe '#make_installed' do
subject { described_class.installed }
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index e50ba67c493..073fbded8ac 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -6,6 +6,7 @@ describe Clusters::Applications::Prometheus do
include_examples 'cluster application core specs', :clusters_applications_prometheus
include_examples 'cluster application status specs', :clusters_applications_prometheus
include_examples 'cluster application helm specs', :clusters_applications_prometheus
+ include_examples 'cluster application initial status specs'
describe '.installed' do
subject { described_class.installed }
@@ -19,20 +20,6 @@ describe Clusters::Applications::Prometheus do
it { is_expected.to contain_exactly(cluster) }
end
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_prometheus, :scheduled, version: '6.7.2') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('6.7.3')
- end
- end
- end
-
describe 'transition to installed' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) }
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 8ad41e997c2..96b7b02dbaf 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -6,23 +6,10 @@ describe Clusters::Applications::Runner do
include_examples 'cluster application core specs', :clusters_applications_runner
include_examples 'cluster application status specs', :clusters_applications_runner
include_examples 'cluster application helm specs', :clusters_applications_runner
+ include_examples 'cluster application initial status specs'
it { is_expected.to belong_to(:runner) }
- describe '#make_installing!' do
- before do
- application.make_installing!
- end
-
- context 'application install previously errored with older version' do
- let(:application) { create(:clusters_applications_runner, :scheduled, version: '0.1.30') }
-
- it 'updates the application version' do
- expect(application.reload.version).to eq('0.1.45')
- end
- end
- end
-
describe '.installed' do
subject { described_class.installed }
diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb
index 005005b236b..12e59b35428 100644
--- a/spec/models/commit_collection_spec.rb
+++ b/spec/models/commit_collection_spec.rb
@@ -35,6 +35,17 @@ describe CommitCollection do
end
end
+ describe '#without_merge_commits' do
+ it 'returns all commits except merge commits' do
+ collection = described_class.new(project, [
+ build(:commit),
+ build(:commit, :merge_commit)
+ ])
+
+ expect(collection.without_merge_commits.size).to eq(1)
+ end
+ end
+
describe '#with_pipeline_status' do
it 'sets the pipeline status for every commit so no additional queries are necessary' do
create(
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 925e2ab0955..447279f19a8 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -60,6 +60,10 @@ describe CacheMarkdownField do
changes_applied
end
end
+
+ def has_attribute?(attr_name)
+ attribute_names.include?(attr_name)
+ end
end
def thing_subclass(new_attr)
@@ -72,7 +76,8 @@ describe CacheMarkdownField do
let(:updated_markdown) { '`Bar`' }
let(:updated_html) { '<p dir="auto"><code>Bar</code></p>' }
- let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
+ let(:cache_version) { CacheMarkdownField::CACHE_COMMONMARK_VERSION << 16 }
before do
stub_commonmark_sourcepos_disabled
@@ -93,24 +98,19 @@ describe CacheMarkdownField do
it { expect(thing.foo).to eq(markdown) }
it { expect(thing.foo_html).to eq(html) }
it { expect(thing.foo_html_changed?).not_to be_truthy }
- it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
+ it { expect(thing.cached_markdown_version).to eq(cache_version) }
end
context 'a changed markdown field' do
- shared_examples 'with cache version' do |cache_version|
- let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
-
- before do
- thing.foo = updated_markdown
- thing.save
- end
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version - 1) }
- it { expect(thing.foo_html).to eq(updated_html) }
- it { expect(thing.cached_markdown_version).to eq(cache_version) }
+ before do
+ thing.foo = updated_markdown
+ thing.save
end
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
+ it { expect(thing.foo_html).to eq(updated_html) }
+ it { expect(thing.cached_markdown_version).to eq(cache_version) }
end
context 'when a markdown field is set repeatedly to an empty string' do
@@ -143,22 +143,17 @@ describe CacheMarkdownField do
end
context 'a non-markdown field changed' do
- shared_examples 'with cache version' do |cache_version|
- let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version - 1) }
- before do
- thing.bar = 'OK'
- thing.save
- end
-
- it { expect(thing.bar).to eq('OK') }
- it { expect(thing.foo).to eq(markdown) }
- it { expect(thing.foo_html).to eq(html) }
- it { expect(thing.cached_markdown_version).to eq(cache_version) }
+ before do
+ thing.bar = 'OK'
+ thing.save
end
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
+ it { expect(thing.bar).to eq('OK') }
+ it { expect(thing.foo).to eq(markdown) }
+ it { expect(thing.foo_html).to eq(html) }
+ it { expect(thing.cached_markdown_version).to eq(cache_version) }
end
context 'version is out of date' do
@@ -169,109 +164,84 @@ describe CacheMarkdownField do
end
it { expect(thing.foo_html).to eq(updated_html) }
- it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
+ it { expect(thing.cached_markdown_version).to eq(cache_version) }
end
describe '#cached_html_up_to_date?' do
- shared_examples 'with cache version' do |cache_version|
- let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
-
- subject { thing.cached_html_up_to_date?(:foo) }
-
- it 'returns false when the version is absent' do
- thing.cached_markdown_version = nil
-
- is_expected.to be_falsy
- end
-
- it 'returns false when the version is too early' do
- thing.cached_markdown_version -= 1
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
- is_expected.to be_falsy
- end
+ subject { thing.cached_html_up_to_date?(:foo) }
- it 'returns false when the version is too late' do
- thing.cached_markdown_version += 1
+ it 'returns false when the version is absent' do
+ thing.cached_markdown_version = nil
- is_expected.to be_falsy
- end
+ is_expected.to be_falsy
+ end
- it 'returns true when the version is just right' do
- thing.cached_markdown_version = cache_version
+ it 'returns false when the cached version is too old' do
+ thing.cached_markdown_version = cache_version - 1
- is_expected.to be_truthy
- end
+ is_expected.to be_falsy
+ end
- it 'returns false if markdown has been changed but html has not' do
- thing.foo = updated_html
+ it 'returns false when the cached version is in future' do
+ thing.cached_markdown_version = cache_version + 1
- is_expected.to be_falsy
- end
+ is_expected.to be_falsy
+ end
- it 'returns true if markdown has not been changed but html has' do
- thing.foo_html = updated_html
+ it 'returns false when the local version was bumped' do
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:local_markdown_version).and_return(2)
+ thing.cached_markdown_version = cache_version
- is_expected.to be_truthy
- end
+ is_expected.to be_falsy
+ end
- it 'returns true if markdown and html have both been changed' do
- thing.foo = updated_markdown
- thing.foo_html = updated_html
+ it 'returns true when the local version is default' do
+ thing.cached_markdown_version = cache_version
- is_expected.to be_truthy
- end
+ is_expected.to be_truthy
+ end
- it 'returns false if the markdown field is set but the html is not' do
- thing.foo_html = nil
+ it 'returns true when the cached version is just right' do
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:local_markdown_version).and_return(2)
+ thing.cached_markdown_version = cache_version + 2
- is_expected.to be_falsy
- end
+ is_expected.to be_truthy
end
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
- end
-
- describe '#latest_cached_markdown_version' do
- subject { thing.latest_cached_markdown_version }
+ it 'returns false if markdown has been changed but html has not' do
+ thing.foo = updated_html
- it 'returns redcarpet version' do
- thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START - 1
- is_expected.to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
+ is_expected.to be_falsy
end
- it 'returns commonmark version' do
- thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START + 1
- is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
- end
+ it 'returns true if markdown has not been changed but html has' do
+ thing.foo_html = updated_html
- it 'returns default version when version is nil' do
- thing.cached_markdown_version = nil
- is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
+ is_expected.to be_truthy
end
- end
- describe '#legacy_markdown?' do
- subject { thing.legacy_markdown? }
+ it 'returns true if markdown and html have both been changed' do
+ thing.foo = updated_markdown
+ thing.foo_html = updated_html
- it 'returns true for redcarpet versions' do
- thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START - 1
is_expected.to be_truthy
end
- it 'returns false for commonmark versions' do
- thing.cached_markdown_version = CacheMarkdownField::CACHE_COMMONMARK_VERSION_START
- is_expected.to be_falsey
- end
+ it 'returns false if the markdown field is set but the html is not' do
+ thing.foo_html = nil
- it 'returns false if nil' do
- thing.cached_markdown_version = nil
- is_expected.to be_falsey
+ is_expected.to be_falsy
end
+ end
- it 'returns false if 0' do
- thing.cached_markdown_version = 0
- is_expected.to be_falsey
+ describe '#latest_cached_markdown_version' do
+ subject { thing.latest_cached_markdown_version }
+
+ it 'returns default version' do
+ thing.cached_markdown_version = nil
+ is_expected.to eq(cache_version)
end
end
@@ -298,44 +268,39 @@ describe CacheMarkdownField do
thing.cached_markdown_version = nil
thing.refresh_markdown_cache
- expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
+ expect(thing.cached_markdown_version).to eq(cache_version)
end
end
describe '#refresh_markdown_cache!' do
- shared_examples 'with cache version' do |cache_version|
- let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: cache_version) }
- before do
- thing.foo = updated_markdown
- end
+ before do
+ thing.foo = updated_markdown
+ end
- it 'fills all html fields' do
- thing.refresh_markdown_cache!
+ it 'fills all html fields' do
+ thing.refresh_markdown_cache!
- expect(thing.foo_html).to eq(updated_html)
- expect(thing.foo_html_changed?).to be_truthy
- expect(thing.baz_html_changed?).to be_truthy
- end
+ expect(thing.foo_html).to eq(updated_html)
+ expect(thing.foo_html_changed?).to be_truthy
+ expect(thing.baz_html_changed?).to be_truthy
+ end
- it 'skips saving if not persisted' do
- expect(thing).to receive(:persisted?).and_return(false)
- expect(thing).not_to receive(:update_columns)
+ it 'skips saving if not persisted' do
+ expect(thing).to receive(:persisted?).and_return(false)
+ expect(thing).not_to receive(:update_columns)
- thing.refresh_markdown_cache!
- end
+ thing.refresh_markdown_cache!
+ end
- it 'saves the changes using #update_columns' do
- expect(thing).to receive(:persisted?).and_return(true)
- expect(thing).to receive(:update_columns)
- .with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => cache_version)
+ it 'saves the changes using #update_columns' do
+ expect(thing).to receive(:persisted?).and_return(true)
+ expect(thing).to receive(:update_columns)
+ .with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => cache_version)
- thing.refresh_markdown_cache!
- end
+ thing.refresh_markdown_cache!
end
-
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_REDCARPET_VERSION
- it_behaves_like 'with cache version', CacheMarkdownField::CACHE_COMMONMARK_VERSION
end
describe '#banzai_render_context' do
@@ -384,7 +349,7 @@ describe CacheMarkdownField do
expect(thing.foo_html).to eq(updated_html)
expect(thing.baz_html).to eq(updated_html)
- expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
+ expect(thing.cached_markdown_version).to eq(cache_version)
end
end
@@ -404,24 +369,8 @@ describe CacheMarkdownField do
expect(thing.foo_html).to eq(updated_html)
expect(thing.baz_html).to eq(updated_html)
- expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
+ expect(thing.cached_markdown_version).to eq(cache_version)
end
end
end
-
- describe CacheMarkdownField::MarkdownEngine do
- subject { lambda { |version| CacheMarkdownField::MarkdownEngine.from_version(version) } }
-
- it 'returns :common_mark as a default' do
- expect(subject.call(nil)).to eq :common_mark
- end
-
- it 'returns :common_mark' do
- expect(subject.call(CacheMarkdownField::CACHE_COMMONMARK_VERSION)).to eq :common_mark
- end
-
- it 'returns :redcarpet' do
- expect(subject.call(CacheMarkdownField::CACHE_REDCARPET_VERSION)).to eq :redcarpet
- end
- end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 5753c646106..41159348e04 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -139,6 +139,78 @@ describe Issuable do
it 'returns issues with a matching description for a query shorter than 3 chars' do
expect(issuable_class.full_search(searchable_issue2.description.downcase)).to eq([searchable_issue2])
end
+
+ context 'when matching columns is "title"' do
+ it 'returns issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title'))
+ .to eq([searchable_issue])
+ end
+
+ it 'returns no issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title'))
+ .to be_empty
+ end
+ end
+
+ context 'when matching columns is "description"' do
+ it 'returns no issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'description'))
+ .to be_empty
+ end
+
+ it 'returns issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'description'))
+ .to eq([searchable_issue])
+ end
+ end
+
+ context 'when matching columns is "title,description"' do
+ it 'returns issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title,description'))
+ .to eq([searchable_issue])
+ end
+
+ it 'returns issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title,description'))
+ .to eq([searchable_issue])
+ end
+ end
+
+ context 'when matching columns is nil"' do
+ it 'returns issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: nil))
+ .to eq([searchable_issue])
+ end
+
+ it 'returns issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: nil))
+ .to eq([searchable_issue])
+ end
+ end
+
+ context 'when matching columns is "invalid"' do
+ it 'returns issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'invalid'))
+ .to eq([searchable_issue])
+ end
+
+ it 'returns issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'invalid'))
+ .to eq([searchable_issue])
+ end
+ end
+
+ context 'when matching columns is "title,invalid"' do
+ it 'returns issues with a matching title' do
+ expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title,invalid'))
+ .to eq([searchable_issue])
+ end
+
+ it 'returns no issues with a matching description' do
+ expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title,invalid'))
+ .to be_empty
+ end
+ end
end
describe '.to_ability_name' do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 9a3f1f1c5a1..2d554326f05 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -41,6 +41,76 @@ describe Environment do
end
end
+ describe '.for_name_like' do
+ subject { project.environments.for_name_like(query, limit: limit) }
+
+ let!(:environment) { create(:environment, name: 'production', project: project) }
+ let(:query) { 'pro' }
+ let(:limit) { 5 }
+
+ it 'returns a found name' do
+ is_expected.to include(environment)
+ end
+
+ context 'when query is production' do
+ let(:query) { 'production' }
+
+ it 'returns a found name' do
+ is_expected.to include(environment)
+ end
+ end
+
+ context 'when query is productionA' do
+ let(:query) { 'productionA' }
+
+ it 'returns empty array' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when query is empty' do
+ let(:query) { '' }
+
+ it 'returns a found name' do
+ is_expected.to include(environment)
+ end
+ end
+
+ context 'when query is nil' do
+ let(:query) { }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(NoMethodError)
+ end
+ end
+
+ context 'when query is partially matched in the middle of environment name' do
+ let(:query) { 'duction' }
+
+ it 'returns empty array' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when query contains a wildcard character' do
+ let(:query) { 'produc%' }
+
+ it 'prevents wildcard injection' do
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ describe '.pluck_names' do
+ subject { described_class.pluck_names }
+
+ let!(:environment) { create(:environment, name: 'production', project: project) }
+
+ it 'plucks names' do
+ is_expected.to eq(%w[production])
+ end
+ end
+
describe '#expire_etag_cache' do
let(:store) { Gitlab::EtagCaching::Store.new }
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index cdd7dea2064..e90319c39b1 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -23,6 +23,41 @@ RSpec.describe GpgSignature do
it { is_expected.to validate_presence_of(:gpg_key_primary_keyid) }
end
+ describe '.safe_create!' do
+ let(:attributes) do
+ {
+ commit_sha: commit_sha,
+ project: project,
+ gpg_key_primary_keyid: gpg_key.keyid
+ }
+ end
+
+ it 'finds a signature by commit sha if it existed' do
+ gpg_signature
+
+ expect(described_class.safe_create!(commit_sha: commit_sha)).to eq(gpg_signature)
+ end
+
+ it 'creates a new signature if it was not found' do
+ expect { described_class.safe_create!(attributes) }.to change { described_class.count }.by(1)
+ end
+
+ it 'assigns the correct attributes when creating' do
+ signature = described_class.safe_create!(attributes)
+
+ expect(signature.project).to eq(project)
+ expect(signature.commit_sha).to eq(commit_sha)
+ expect(signature.gpg_key_primary_keyid).to eq(gpg_key.keyid)
+ end
+
+ it 'does not raise an error in case of a race condition' do
+ expect(described_class).to receive(:find_or_create_by).and_raise(ActiveRecord::RecordNotUnique)
+ allow(described_class).to receive(:find_or_create_by).and_call_original
+
+ described_class.safe_create!(attributes)
+ end
+ end
+
describe '#commit' do
it 'fetches the commit through the project' do
expect_any_instance_of(Project).to receive(:commit).with(commit_sha).and_return(commit)
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 33e984dc399..1849d3bac12 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -46,7 +46,7 @@ describe MergeRequestDiff do
it { expect(first_diff.reload).not_to be_latest }
end
- describe '#diffs' do
+ shared_examples_for 'merge request diffs' do
let(:merge_request) { create(:merge_request, :with_diffs) }
let!(:diff) { merge_request.merge_request_diff.reload }
@@ -91,98 +91,110 @@ describe MergeRequestDiff do
diff.diffs.diff_files
end
end
- end
- describe '#raw_diffs' do
- context 'when the :ignore_whitespace_change option is set' do
- it 'creates a new compare object instead of loading from the DB' do
- expect(diff_with_commits).not_to receive(:load_diffs)
- expect(diff_with_commits.compare).to receive(:diffs).and_call_original
+ describe '#raw_diffs' do
+ context 'when the :ignore_whitespace_change option is set' do
+ it 'creates a new compare object instead of using preprocessed data' do
+ expect(diff_with_commits).not_to receive(:load_diffs)
+ expect(diff_with_commits.compare).to receive(:diffs).and_call_original
- diff_with_commits.raw_diffs(ignore_whitespace_change: true)
+ diff_with_commits.raw_diffs(ignore_whitespace_change: true)
+ end
end
- end
- context 'when the raw diffs are empty' do
- before do
- MergeRequestDiffFile.where(merge_request_diff_id: diff_with_commits.id).delete_all
- end
+ context 'when the raw diffs are empty' do
+ before do
+ MergeRequestDiffFile.where(merge_request_diff_id: diff_with_commits.id).delete_all
+ end
- it 'returns an empty DiffCollection' do
- expect(diff_with_commits.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
- expect(diff_with_commits.raw_diffs).to be_empty
+ it 'returns an empty DiffCollection' do
+ expect(diff_with_commits.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
+ expect(diff_with_commits.raw_diffs).to be_empty
+ end
end
- end
- context 'when the raw diffs exist' do
- it 'returns the diffs' do
- expect(diff_with_commits.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
- expect(diff_with_commits.raw_diffs).not_to be_empty
- end
+ context 'when the raw diffs exist' do
+ it 'returns the diffs' do
+ expect(diff_with_commits.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
+ expect(diff_with_commits.raw_diffs).not_to be_empty
+ end
- context 'when the :paths option is set' do
- let(:diffs) { diff_with_commits.raw_diffs(paths: ['files/ruby/popen.rb', 'files/ruby/popen.rb']) }
+ context 'when the :paths option is set' do
+ let(:diffs) { diff_with_commits.raw_diffs(paths: ['files/ruby/popen.rb', 'files/ruby/popen.rb']) }
- it 'only returns diffs that match the (old path, new path) given' do
- expect(diffs.map(&:new_path)).to contain_exactly('files/ruby/popen.rb')
- end
+ it 'only returns diffs that match the (old path, new path) given' do
+ expect(diffs.map(&:new_path)).to contain_exactly('files/ruby/popen.rb')
+ end
- it 'only serializes diff files found by query' do
- expect(diff_with_commits.merge_request_diff_files.count).to be > 10
- expect_any_instance_of(MergeRequestDiffFile).to receive(:to_hash).once
+ it 'only serializes diff files found by query' do
+ expect(diff_with_commits.merge_request_diff_files.count).to be > 10
+ expect_any_instance_of(MergeRequestDiffFile).to receive(:to_hash).once
- diffs
- end
+ diffs
+ end
- it 'uses the diffs from the DB' do
- expect(diff_with_commits).to receive(:load_diffs)
+ it 'uses the preprocessed diffs' do
+ expect(diff_with_commits).to receive(:load_diffs)
- diffs
+ diffs
+ end
end
end
end
- end
- describe '#save_diffs' do
- it 'saves collected state' do
- mr_diff = create(:merge_request).merge_request_diff
+ describe '#save_diffs' do
+ it 'saves collected state' do
+ mr_diff = create(:merge_request).merge_request_diff
- expect(mr_diff.collected?).to be_truthy
- end
+ expect(mr_diff.collected?).to be_truthy
+ end
- it 'saves overflow state' do
- allow(Commit).to receive(:max_diff_options)
- .and_return(max_lines: 0, max_files: 0)
+ it 'saves overflow state' do
+ allow(Commit).to receive(:max_diff_options)
+ .and_return(max_lines: 0, max_files: 0)
- mr_diff = create(:merge_request).merge_request_diff
+ mr_diff = create(:merge_request).merge_request_diff
- expect(mr_diff.overflow?).to be_truthy
- end
+ expect(mr_diff.overflow?).to be_truthy
+ end
- it 'saves empty state' do
- allow_any_instance_of(described_class).to receive_message_chain(:compare, :commits)
- .and_return([])
+ it 'saves empty state' do
+ allow_any_instance_of(described_class).to receive_message_chain(:compare, :commits)
+ .and_return([])
- mr_diff = create(:merge_request).merge_request_diff
+ mr_diff = create(:merge_request).merge_request_diff
- expect(mr_diff.empty?).to be_truthy
- end
+ expect(mr_diff.empty?).to be_truthy
+ end
- it 'expands collapsed diffs before saving' do
- mr_diff = create(:merge_request, source_branch: 'expand-collapse-lines', target_branch: 'master').merge_request_diff
- diff_file = mr_diff.merge_request_diff_files.find_by(new_path: 'expand-collapse/file-5.txt')
+ it 'expands collapsed diffs before saving' do
+ mr_diff = create(:merge_request, source_branch: 'expand-collapse-lines', target_branch: 'master').merge_request_diff
+ diff_file = mr_diff.merge_request_diff_files.find_by(new_path: 'expand-collapse/file-5.txt')
- expect(diff_file.diff).not_to be_empty
+ expect(diff_file.diff).not_to be_empty
+ end
+
+ it 'saves binary diffs correctly' do
+ path = 'files/images/icn-time-tracking.pdf'
+ mr_diff = create(:merge_request, source_branch: 'add-pdf-text-binary', target_branch: 'master').merge_request_diff
+ diff_file = mr_diff.merge_request_diff_files.find_by(new_path: path)
+
+ expect(diff_file).to be_binary
+ expect(diff_file.diff).to eq(mr_diff.compare.diffs(paths: [path]).to_a.first.diff)
+ end
end
+ end
- it 'saves binary diffs correctly' do
- path = 'files/images/icn-time-tracking.pdf'
- mr_diff = create(:merge_request, source_branch: 'add-pdf-text-binary', target_branch: 'master').merge_request_diff
- diff_file = mr_diff.merge_request_diff_files.find_by(new_path: path)
+ describe 'internal diffs configured' do
+ include_examples 'merge request diffs'
+ end
- expect(diff_file).to be_binary
- expect(diff_file.diff).to eq(mr_diff.compare.diffs(paths: [path]).to_a.first.diff)
+ describe 'external diffs configured' do
+ before do
+ stub_external_diffs_setting(enabled: true)
end
+
+ include_examples 'merge request diffs'
end
describe '#commit_shas' do
@@ -245,4 +257,55 @@ describe MergeRequestDiff do
expect(subject.modified_paths).to eq(%w{foo bar baz})
end
end
+
+ describe '#opening_external_diff' do
+ subject(:diff) { diff_with_commits }
+
+ context 'external diffs disabled' do
+ it { expect(diff.external_diff).not_to be_exists }
+
+ it 'yields nil' do
+ expect { |b| diff.opening_external_diff(&b) }.to yield_with_args(nil)
+ end
+ end
+
+ context 'external diffs enabled' do
+ let(:test_dir) { 'tmp/tests/external-diffs' }
+
+ around do |example|
+ FileUtils.mkdir_p(test_dir)
+
+ begin
+ example.run
+ ensure
+ FileUtils.rm_rf(test_dir)
+ end
+ end
+
+ before do
+ stub_external_diffs_setting(enabled: true, storage_path: test_dir)
+ end
+
+ it { expect(diff.external_diff).to be_exists }
+
+ it 'yields an open file' do
+ expect { |b| diff.opening_external_diff(&b) }.to yield_with_args(File)
+ end
+
+ it 'is re-entrant' do
+ outer_file_a =
+ diff.opening_external_diff do |outer_file|
+ diff.opening_external_diff do |inner_file|
+ expect(outer_file).to eq(inner_file)
+ end
+
+ outer_file
+ end
+
+ diff.opening_external_diff do |outer_file_b|
+ expect(outer_file_a).not_to eq(outer_file_b)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index b62f973ad1e..afa87b8a62d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -82,6 +82,38 @@ describe MergeRequest do
end
end
+ describe '#default_squash_commit_message' do
+ let(:project) { subject.project }
+
+ def commit_collection(commit_hashes)
+ raw_commits = commit_hashes.map { |raw| Commit.from_hash(raw, project) }
+
+ CommitCollection.new(project, raw_commits)
+ end
+
+ it 'returns the oldest multiline commit message' do
+ commits = commit_collection([
+ { message: 'Singleline', parent_ids: [] },
+ { message: "Second multiline\nCommit message", parent_ids: [] },
+ { message: "First multiline\nCommit message", parent_ids: [] }
+ ])
+
+ expect(subject).to receive(:commits).and_return(commits)
+
+ expect(subject.default_squash_commit_message).to eq("First multiline\nCommit message")
+ end
+
+ it 'returns the merge request title if there are no multiline commits' do
+ commits = commit_collection([
+ { message: 'Singleline', parent_ids: [] }
+ ])
+
+ expect(subject).to receive(:commits).and_return(commits)
+
+ expect(subject.default_squash_commit_message).to eq(subject.title)
+ end
+ end
+
describe 'modules' do
subject { described_class }
@@ -920,18 +952,18 @@ describe MergeRequest do
end
end
- describe '#merge_commit_message' do
+ describe '#default_merge_commit_message' do
it 'includes merge information as the title' do
request = build(:merge_request, source_branch: 'source', target_branch: 'target')
- expect(request.merge_commit_message)
+ expect(request.default_merge_commit_message)
.to match("Merge branch 'source' into 'target'\n\n")
end
it 'includes its title in the body' do
request = build(:merge_request, title: 'Remove all technical debt')
- expect(request.merge_commit_message)
+ expect(request.default_merge_commit_message)
.to match("Remove all technical debt\n\n")
end
@@ -943,34 +975,34 @@ describe MergeRequest do
allow(subject.project).to receive(:default_branch).and_return(subject.target_branch)
subject.cache_merge_request_closes_issues!
- expect(subject.merge_commit_message)
+ expect(subject.default_merge_commit_message)
.to match("Closes #{issue.to_reference}")
end
it 'includes its reference in the body' do
request = build_stubbed(:merge_request)
- expect(request.merge_commit_message)
+ expect(request.default_merge_commit_message)
.to match("See merge request #{request.to_reference(full: true)}")
end
it 'excludes multiple linebreak runs when description is blank' do
request = build(:merge_request, title: 'Title', description: nil)
- expect(request.merge_commit_message).not_to match("Title\n\n\n\n")
+ expect(request.default_merge_commit_message).not_to match("Title\n\n\n\n")
end
it 'includes its description in the body' do
request = build(:merge_request, description: 'By removing all code')
- expect(request.merge_commit_message(include_description: true))
+ expect(request.default_merge_commit_message(include_description: true))
.to match("By removing all code\n\n")
end
it 'does not includes its description in the body' do
request = build(:merge_request, description: 'By removing all code')
- expect(request.merge_commit_message)
+ expect(request.default_merge_commit_message)
.not_to match("By removing all code\n\n")
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index ae137aa7b78..c1767ed0535 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1765,7 +1765,7 @@ describe Project do
context 'using a regular repository' do
it 'creates the repository' do
expect(shell).to receive(:create_repository)
- .with(project.repository_storage, project.disk_path)
+ .with(project.repository_storage, project.disk_path, project.full_path)
.and_return(true)
expect(project.repository).to receive(:after_create)
@@ -1775,7 +1775,7 @@ describe Project do
it 'adds an error if the repository could not be created' do
expect(shell).to receive(:create_repository)
- .with(project.repository_storage, project.disk_path)
+ .with(project.repository_storage, project.disk_path, project.full_path)
.and_return(false)
expect(project.repository).not_to receive(:after_create)
@@ -1808,7 +1808,7 @@ describe Project do
.and_return(false)
allow(shell).to receive(:create_repository)
- .with(project.repository_storage, project.disk_path)
+ .with(project.repository_storage, project.disk_path, project.full_path)
.and_return(true)
expect(project).to receive(:create_repository).with(force: true)
@@ -1832,7 +1832,7 @@ describe Project do
.and_return(false)
expect(shell).to receive(:create_repository)
- .with(project.repository_storage, project.disk_path)
+ .with(project.repository_storage, project.disk_path, project.full_path)
.and_return(true)
project.ensure_repository
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 48a43801b9f..3ccc706edf2 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -7,7 +7,7 @@ describe ProjectWiki do
let(:repository) { project.repository }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_wiki) { described_class.new(project, user) }
- let(:raw_repository) { Gitlab::Git::Repository.new(project.repository_storage, subject.disk_path + '.git', 'foo') }
+ let(:raw_repository) { Gitlab::Git::Repository.new(project.repository_storage, subject.disk_path + '.git', 'foo', 'group/project.wiki') }
let(:commit) { project_wiki.repository.head_commit }
subject { project_wiki }
@@ -75,7 +75,7 @@ describe ProjectWiki do
# Create a fresh project which will not have a wiki
project_wiki = described_class.new(create(:project), user)
gitlab_shell = double(:gitlab_shell)
- allow(gitlab_shell).to receive(:create_repository)
+ allow(gitlab_shell).to receive(:create_wiki_repository)
allow(project_wiki).to receive(:gitlab_shell).and_return(gitlab_shell)
expect { project_wiki.send(:wiki) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 4978c43c9b5..f78760bf567 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -2291,6 +2291,7 @@ describe Repository do
expect(subject).to be_a(Gitlab::Git::Repository)
expect(subject.relative_path).to eq(project.disk_path + '.git')
expect(subject.gl_repository).to eq("project-#{project.id}")
+ expect(subject.gl_project_path).to eq(project.full_path)
end
context 'with a wiki repository' do
@@ -2300,6 +2301,7 @@ describe Repository do
expect(subject).to be_a(Gitlab::Git::Repository)
expect(subject.relative_path).to eq(project.disk_path + '.wiki.git')
expect(subject.gl_repository).to eq("wiki-#{project.id}")
+ expect(subject.gl_project_path).to eq(project.full_path)
end
end
end
diff --git a/spec/models/resource_label_event_spec.rb b/spec/models/resource_label_event_spec.rb
index 3797960ac3d..7eeb2fae57d 100644
--- a/spec/models/resource_label_event_spec.rb
+++ b/spec/models/resource_label_event_spec.rb
@@ -81,14 +81,14 @@ RSpec.describe ResourceLabelEvent, type: :model do
expect(subject.outdated_markdown?).to be true
end
- it 'returns true markdown is outdated' do
- subject.attributes = { cached_markdown_version: 0 }
+ it 'returns true if markdown is outdated' do
+ subject.attributes = { cached_markdown_version: ((CacheMarkdownField::CACHE_COMMONMARK_VERSION - 1) << 16) | 0 }
expect(subject.outdated_markdown?).to be true
end
it 'returns false if label and reference are set' do
- subject.attributes = { reference: 'whatever', cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION }
+ subject.attributes = { reference: 'whatever', cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION << 16 }
expect(subject.outdated_markdown?).to be false
end
diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb
index 677613b7980..6c35ed8f649 100644
--- a/spec/models/sent_notification_spec.rb
+++ b/spec/models/sent_notification_spec.rb
@@ -36,19 +36,41 @@ describe SentNotification do
end
end
+ shared_examples 'a successful sent notification' do
+ it 'creates a new SentNotification' do
+ expect { subject }.to change { described_class.count }.by(1)
+ end
+ end
+
describe '.record' do
let(:issue) { create(:issue) }
- it 'creates a new SentNotification' do
- expect { described_class.record(issue, user.id) }.to change { described_class.count }.by(1)
- end
+ subject { described_class.record(issue, user.id) }
+
+ it_behaves_like 'a successful sent notification'
end
describe '.record_note' do
- let(:note) { create(:diff_note_on_merge_request) }
+ subject { described_class.record_note(note, note.author.id) }
- it 'creates a new SentNotification' do
- expect { described_class.record_note(note, note.author.id) }.to change { described_class.count }.by(1)
+ context 'for a discussion note' do
+ let(:note) { create(:diff_note_on_merge_request) }
+
+ it_behaves_like 'a successful sent notification'
+
+ it 'sets in_reply_to_discussion_id' do
+ expect(subject.in_reply_to_discussion_id).to eq(note.discussion_id)
+ end
+ end
+
+ context 'for an individual note' do
+ let(:note) { create(:note_on_merge_request) }
+
+ it_behaves_like 'a successful sent notification'
+
+ it 'does not set in_reply_to_discussion_id' do
+ expect(subject.in_reply_to_discussion_id).to be_nil
+ end
end
end
diff --git a/spec/models/ssh_host_key_spec.rb b/spec/models/ssh_host_key_spec.rb
index 23a94334172..4c677569561 100644
--- a/spec/models/ssh_host_key_spec.rb
+++ b/spec/models/ssh_host_key_spec.rb
@@ -56,6 +56,29 @@ describe SshHostKey do
end
end
+ describe '.find_by' do
+ let(:project) { create(:project) }
+ let(:url) { 'ssh://invalid.invalid:2222' }
+
+ let(:finding_id) { [project.id, url].join(':') }
+
+ it 'accepts a string key' do
+ result = described_class.find_by('id' => finding_id)
+
+ expect(result).to be_a(described_class)
+ expect(result.project).to eq(project)
+ expect(result.url.to_s).to eq(url)
+ end
+
+ it 'accepts a symbol key' do
+ result = described_class.find_by(id: finding_id)
+
+ expect(result).to be_a(described_class)
+ expect(result.project).to eq(project)
+ expect(result.url.to_s).to eq(url)
+ end
+ end
+
describe '#fingerprints', :use_clean_rails_memory_store_caching do
it 'returns an array of indexed fingerprints when the cache is filled' do
stub_reactive_cache(ssh_host_key, known_hosts: known_hosts)