summaryrefslogtreecommitdiff
path: root/spec/lib
diff options
context:
space:
mode:
authorMike Lewis <mlewis@gitlab.com>2019-03-07 15:59:00 +0000
committerMike Lewis <mlewis@gitlab.com>2019-03-07 15:59:00 +0000
commitdbd7309a16bd3abc6c586b6c2df2beb317cfef95 (patch)
tree3fdd719c926ac80285f0dc93ef975625657d0fbb /spec/lib
parent7be248334b350091e83d0335bf0c263071c6a67f (diff)
parentb63efb09a5c864047924cd2d84527b47dd563d5f (diff)
downloadgitlab-ce-reply-to-comment-documentation.tar.gz
Merge branch 'master' into 'reply-to-comment-documentation'reply-to-comment-documentation
# Conflicts: # doc/user/discussions/index.md
Diffstat (limited to 'spec/lib')
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb4
-rw-r--r--spec/lib/event_filter_spec.rb8
-rw-r--r--spec/lib/gitlab/auth/ldap/config_spec.rb153
-rw-r--r--spec/lib/gitlab/checks/branch_check_spec.rb124
-rw-r--r--spec/lib/gitlab/ci/build/policy/changes_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/policy/refs_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/build/policy/variables_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/config/external/file/project_spec.rb47
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/external/file/template_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb82
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/build_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/templates_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/variables/collection/item_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/variables/collection_spec.rb12
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb2
-rw-r--r--spec/lib/gitlab/danger/helper_spec.rb1
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb4
-rw-r--r--spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb9
-rw-r--r--spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb4
-rw-r--r--spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb18
-rw-r--r--spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb44
-rw-r--r--spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb5
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb4
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb201
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb16
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb16
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb10
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb74
-rw-r--r--spec/lib/gitlab/gitaly_client/storage_settings_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb24
-rw-r--r--spec/lib/gitlab/hashed_storage/migrator_spec.rb114
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml2
-rw-r--r--spec/lib/gitlab/import_export/merge_request_parser_spec.rb16
-rw-r--r--spec/lib/gitlab/json_cache_spec.rb28
-rw-r--r--spec/lib/gitlab/kubernetes/kube_client_spec.rb30
-rw-r--r--spec/lib/gitlab/path_regex_spec.rb2
-rw-r--r--spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb4
-rw-r--r--spec/lib/gitlab/quick_actions/command_definition_spec.rb7
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb74
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/shutdown_spec.rb88
-rw-r--r--spec/lib/gitlab/sidekiq_signals_spec.rb69
-rw-r--r--spec/lib/gitlab_spec.rb14
-rw-r--r--spec/lib/object_storage/direct_upload_spec.rb2
49 files changed, 1315 insertions, 245 deletions
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index c96e7ab8495..3496b01ebcc 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -16,6 +16,10 @@ describe Constraints::ProjectUrlConstrainer do
let(:request) { build_request('foo', 'bar') }
it { expect(subject.matches?(request)).to be_falsey }
+
+ context 'existence_check is false' do
+ it { expect(subject.matches?(request, existence_check: false)).to be_truthy }
+ end
end
context "project id ending with .git" do
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index 30016da6828..6648e141b7a 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -26,10 +26,10 @@ describe EventFilter do
set(:push_event) { create(:push_event, project: public_project) }
set(:merged_event) { create(:event, :merged, project: public_project, target: public_project) }
- set(:created_event) { create(:event, :created, project: public_project, target: public_project) }
- set(:updated_event) { create(:event, :updated, project: public_project, target: public_project) }
- set(:closed_event) { create(:event, :closed, project: public_project, target: public_project) }
- set(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project) }
+ set(:created_event) { create(:event, :created, project: public_project, target: create(:issue, project: public_project)) }
+ set(:updated_event) { create(:event, :updated, project: public_project, target: create(:issue, project: public_project)) }
+ set(:closed_event) { create(:event, :closed, project: public_project, target: create(:issue, project: public_project)) }
+ set(:reopened_event) { create(:event, :reopened, project: public_project, target: create(:issue, project: public_project)) }
set(:comments_event) { create(:event, :commented, project: public_project, target: public_project) }
set(:joined_event) { create(:event, :joined, project: public_project, target: public_project) }
set(:left_event) { create(:event, :left, project: public_project, target: public_project) }
diff --git a/spec/lib/gitlab/auth/ldap/config_spec.rb b/spec/lib/gitlab/auth/ldap/config_spec.rb
index d3ab599d5a0..b91a09e3137 100644
--- a/spec/lib/gitlab/auth/ldap/config_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/config_spec.rb
@@ -5,6 +5,65 @@ describe Gitlab::Auth::LDAP::Config do
let(:config) { described_class.new('ldapmain') }
+ def raw_cert
+ <<-EOS
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk4CCQDX+u/9fICksDANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV
+UzEMMAoGA1UECAwDRm9vMQwwCgYDVQQHDANCYXIxDDAKBgNVBAoMA0JhejEMMAoG
+A1UECwwDUXV4MQ0wCwYDVQQDDARsZGFwMR8wHQYJKoZIhvcNAQkBFhBsZGFwQGV4
+YW1wbGUuY29tMB4XDTE5MDIyNzE1NTUxNFoXDTE5MDMyOTE1NTUxNFowdTELMAkG
+A1UEBhMCVVMxDDAKBgNVBAgMA0ZvbzEMMAoGA1UEBwwDQmFyMQwwCgYDVQQKDANC
+YXoxDDAKBgNVBAsMA1F1eDENMAsGA1UEAwwEbGRhcDEfMB0GCSqGSIb3DQEJARYQ
+bGRhcEBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+APuDB/4/AUmTEmhYzN13no4Kt8hkRbLQuENRHlOeQw05/MVdoB1AWLOPzIXn4kex
+GD9tHkoJl8S0QPmAAcPHn5O97e+gd0ze5dRQZl/cSd2/j5zeaMvZ1mCrPN/dOluM
+94Oj+wQU4bEcOlrqIMSh0ezJw10R3IHXCQFeGtIZU57WmKcrryQX4kP7KTOgRw/t
+CYp+NivQHtLbBEj1MU0l10qMS2+w8Qpqov4MdW4gx4wTgId2j1ZZ56+n6Jsc9qoI
+wBWBNL4XU5a3kwhYZDOJoOvI9po33KLdT1dXS81uOFXClp3LGmKDgLTwQ1w+RmQG
++JG4EvTfDIShdcTDXEaOfCECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAJM9Btu5g
+k8qDiz5TilvpyoGuI4viCwusARFAFmOB/my/cHlVvkuq4bbfV1KJoWWGJg8GcklL
+cnIdxc35uYM5icr6xXQyrW0GqAO+LEXyUxVQqYETxrQ/LJ03xhBnuF7hvZJIBiky
+GwUy0clJxGfaCeEM8zXwePawLgGjuUawDDQOwigysoWqoMu3VFW8zl8UPa84bow9
+Kn2QmPAkLw4EcqYSCNSSvnyzu5SM64jwLWRXFsmlqD7773oT29vTkqM1EQANFEfT
+7gQomLyPqoPBoFph5oSNn6Rf31QX1Sie92EAKVnZ1XmD68hKzjv6ChCtzTv4jABg
+XrDwnLkORIAF/Q==
+-----END CERTIFICATE-----
+ EOS
+ end
+
+ def raw_key
+ <<-EOS
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQD7gwf+PwFJkxJo
+WMzdd56OCrfIZEWy0LhDUR5TnkMNOfzFXaAdQFizj8yF5+JHsRg/bR5KCZfEtED5
+gAHDx5+Tve3voHdM3uXUUGZf3Endv4+c3mjL2dZgqzzf3TpbjPeDo/sEFOGxHDpa
+6iDEodHsycNdEdyB1wkBXhrSGVOe1pinK68kF+JD+ykzoEcP7QmKfjYr0B7S2wRI
+9TFNJddKjEtvsPEKaqL+DHVuIMeME4CHdo9WWeevp+ibHPaqCMAVgTS+F1OWt5MI
+WGQziaDryPaaN9yi3U9XV0vNbjhVwpadyxpig4C08ENcPkZkBviRuBL03wyEoXXE
+w1xGjnwhAgMBAAECggEAbw82GVui6uUpjLAhjm3CssAi1TcJ2+L0aq1IMe5Bd3ay
+mkg0apY+VNPboQl6zuNxbJh3doPz42UhB8sxfE0Ktwd4KIb4Bxap7+2stwmkCGoN
+NVy0c8d2NWuHzuZ2XXTK2vMu5Wd/HWD0l66o14sJEoEpZlB7yU216UevmjSayxjh
+aBTSaYyyrf24haTaCuqwph/V73ZlMpFdSALGny0uiP/5inxciMCkMpHfX6BflSb4
+EGKsIYt9BJ0kY4GNG5bCP7971UCxp2eEJhU2fV8HuFGCOD12IqSpUqPxHxjsWpfx
+T7FZ3V2kM/58Ca+5LB2y3atcPIdY0/g7/43V4VD+7QKBgQD/PO4/0cmZuuLU1LPT
+C/C596kPK0JLlvvRqhbz4byRAkW/n7uQFG7TMtFNle3UmT7rk7pjtbHnByqzEd+9
+jMhBysjHOMg0+DWm7fEtSg/tJ3qLVO3nbdA4qmXYobLcLoG+PCYRLskEHHqTG/Bv
+QZLbavOU6rrTqckNr1TMpNBmXwKBgQD8Q0C2YTOpwgjRUe8i6Chnc3o4x8a1i98y
+9la6c7y7acWHSbEczMkNfEBrbM73rTb+bBA0Zqw+Z1gkv8bGpvGxX8kbSfJJ2YKW
+9koxpLNTVNVapqBa9ImiaozV285dz9Ukx8bnMOJlTELpOl7RRV7iF0smYjfHIl3D
+Yxyda/MtfwKBgHb9l/Dmw77IkqE4PFFimqqIHCe3OiP1UpavXh36midcUNoCBLYp
+4HTTlyI9iG/5tYysBVQgy7xx6eUrqww6Ss3pVOsTvLp9EL4u5aYAhiZApm+4e2TO
+HCmevvZcg/8EK3Zdoj2Wex5QjJBykQe9IVLrrH07ZTfySon3uGfjWkivAoGAGvqS
+VC8HGHOw/7n0ilYr5Ax8mM/813OzFj80PVKdb6m7P2HJOFxKcE/Gj/aeF+0FgaZL
+AV+tsirZSWzdNGesV5z35Bw/dlh11/FVNAP6TcI34y8I3VFj2uPsVf7hDjVpBTr8
+ccNPoyfJzCm69ESoBiQZnGxKrNhnELtr1wYxhr8CgYApWwf4hVrTWV1zs+pEJenh
+AtlErSqafbECNDSwS5BX8yDpu5yRBJ4xegO/rNlmb8ICRYkuJapD1xXicFOsmfUK
+0Ff8afd2Q/OfBeUdq9KA4JO9fNqzEwOWvv8Ryn4ZSYcAuLP7IVJKjjI6R7rYaO/G
+3OWJdizbykGOi0BFDu+3dw==
+-----END PRIVATE KEY-----
+ EOS
+ end
+
describe '.servers' do
it 'returns empty array if no server information is available' do
allow(Gitlab.config).to receive(:ldap).and_return('enabled' => false)
@@ -89,6 +148,42 @@ describe Gitlab::Auth::LDAP::Config do
expect(config.adapter_options[:encryption]).to include({ method: :start_tls })
end
+ it 'transforms SSL cert and key to OpenSSL objects' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'start_tls',
+ 'tls_options' => {
+ 'cert' => raw_cert,
+ 'key' => raw_key
+ }
+ }
+ )
+
+ expect(config.adapter_options[:encryption][:tls_options][:cert]).to be_a(OpenSSL::X509::Certificate)
+ expect(config.adapter_options[:encryption][:tls_options][:key]).to be_a(OpenSSL::PKey::RSA)
+ end
+
+ it 'logs an error when an invalid key or cert are configured' do
+ allow(Rails.logger).to receive(:error)
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'start_tls',
+ 'tls_options' => {
+ 'cert' => 'invalid cert',
+ 'key' => 'invalid_key'
+ }
+ }
+ )
+
+ config.adapter_options
+
+ expect(Rails.logger).to have_received(:error).with(/LDAP TLS Options/).twice
+ end
+
context 'when verify_certificates is enabled' do
it 'sets tls_options to OpenSSL defaults' do
stub_ldap_config(
@@ -130,7 +225,9 @@ describe Gitlab::Auth::LDAP::Config do
'host' => 'ldap.example.com',
'port' => 686,
'encryption' => 'simple_tls',
- 'ca_file' => '/etc/ca.pem'
+ 'tls_options' => {
+ 'ca_file' => '/etc/ca.pem'
+ }
}
)
@@ -145,7 +242,9 @@ describe Gitlab::Auth::LDAP::Config do
'host' => 'ldap.example.com',
'port' => 686,
'encryption' => 'simple_tls',
- 'ca_file' => ' '
+ 'tls_options' => {
+ 'ca_file' => ' '
+ }
}
)
@@ -160,7 +259,9 @@ describe Gitlab::Auth::LDAP::Config do
'host' => 'ldap.example.com',
'port' => 686,
'encryption' => 'simple_tls',
- 'ssl_version' => 'TLSv1_2'
+ 'tls_options' => {
+ 'ssl_version' => 'TLSv1_2'
+ }
}
)
@@ -175,7 +276,9 @@ describe Gitlab::Auth::LDAP::Config do
'host' => 'ldap.example.com',
'port' => 686,
'encryption' => 'simple_tls',
- 'ssl_version' => ' '
+ 'tls_options' => {
+ 'ssl_version' => ' '
+ }
}
)
@@ -223,6 +326,23 @@ describe Gitlab::Auth::LDAP::Config do
)
end
+ it 'transforms SSL cert and key to OpenSSL objects' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'start_tls',
+ 'tls_options' => {
+ 'cert' => raw_cert,
+ 'key' => raw_key
+ }
+ }
+ )
+
+ expect(config.omniauth_options[:tls_options][:cert]).to be_a(OpenSSL::X509::Certificate)
+ expect(config.omniauth_options[:tls_options][:key]).to be_a(OpenSSL::PKey::RSA)
+ end
+
context 'when verify_certificates is enabled' do
it 'specifies disable_verify_certificates as false' do
stub_ldap_config(
@@ -261,11 +381,13 @@ describe Gitlab::Auth::LDAP::Config do
'port' => 686,
'encryption' => 'simple_tls',
'verify_certificates' => true,
- 'ca_file' => '/etc/ca.pem'
+ 'tls_options' => {
+ 'ca_file' => '/etc/ca.pem'
+ }
}
)
- expect(config.omniauth_options).to include({ ca_file: '/etc/ca.pem' })
+ expect(config.omniauth_options[:tls_options]).to include({ ca_file: '/etc/ca.pem' })
end
end
@@ -277,11 +399,13 @@ describe Gitlab::Auth::LDAP::Config do
'port' => 686,
'encryption' => 'simple_tls',
'verify_certificates' => true,
- 'ca_file' => ' '
+ 'tls_options' => {
+ 'ca_file' => ' '
+ }
}
)
- expect(config.omniauth_options).not_to have_key(:ca_file)
+ expect(config.omniauth_options[:tls_options]).not_to have_key(:ca_file)
end
end
@@ -293,11 +417,13 @@ describe Gitlab::Auth::LDAP::Config do
'port' => 686,
'encryption' => 'simple_tls',
'verify_certificates' => true,
- 'ssl_version' => 'TLSv1_2'
+ 'tls_options' => {
+ 'ssl_version' => 'TLSv1_2'
+ }
}
)
- expect(config.omniauth_options).to include({ ssl_version: 'TLSv1_2' })
+ expect(config.omniauth_options[:tls_options]).to include({ ssl_version: 'TLSv1_2' })
end
end
@@ -309,11 +435,14 @@ describe Gitlab::Auth::LDAP::Config do
'port' => 686,
'encryption' => 'simple_tls',
'verify_certificates' => true,
- 'ssl_version' => ' '
+ 'tls_options' => {
+ 'ssl_version' => ' '
+ }
}
)
- expect(config.omniauth_options).not_to have_key(:ssl_version)
+ # OpenSSL default params includes `ssl_version` so we just check that it's not blank
+ expect(config.omniauth_options[:tls_options]).not_to include({ ssl_version: ' ' })
end
end
end
diff --git a/spec/lib/gitlab/checks/branch_check_spec.rb b/spec/lib/gitlab/checks/branch_check_spec.rb
index 77366e91dca..12beeecd470 100644
--- a/spec/lib/gitlab/checks/branch_check_spec.rb
+++ b/spec/lib/gitlab/checks/branch_check_spec.rb
@@ -48,10 +48,128 @@ describe Gitlab::Checks::BranchCheck do
context 'when project repository is empty' do
let(:project) { create(:project) }
- it 'raises an error if the user is not allowed to push to protected branches' do
- expect(user_access).to receive(:can_push_to_branch?).and_return(false)
+ context 'user is not allowed to push to protected branches' do
+ before do
+ allow(user_access)
+ .to receive(:can_push_to_branch?)
+ .and_return(false)
+ end
+
+ it 'raises an error' do
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /Ask a project Owner or Maintainer to create a default branch/)
+ end
+ end
+
+ context 'user is allowed to push to protected branches' do
+ before do
+ allow(user_access)
+ .to receive(:can_push_to_branch?)
+ .and_return(true)
+ end
+
+ it 'allows branch creation' do
+ expect { subject.validate! }.not_to raise_error
+ end
+ end
+ end
+
+ context 'branch creation' do
+ let(:oldrev) { '0000000000000000000000000000000000000000' }
+ let(:ref) { 'refs/heads/feature' }
- expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /Ask a project Owner or Maintainer to create a default branch/)
+ context 'protected branch creation feature is disabled' do
+ before do
+ stub_feature_flags(protected_branch_creation: false)
+ end
+
+ context 'user is not allowed to push to protected branch' do
+ before do
+ allow(user_access)
+ .to receive(:can_push_to_branch?)
+ .and_return(false)
+ end
+
+ it 'raises an error' do
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to protected branches on this project.')
+ end
+ end
+
+ context 'user is allowed to push to protected branch' do
+ before do
+ allow(user_access)
+ .to receive(:can_push_to_branch?)
+ .and_return(true)
+ end
+
+ it 'does not raise an error' do
+ expect { subject.validate! }.not_to raise_error
+ end
+ end
+ end
+
+ context 'protected branch creation feature is enabled' do
+ context 'user is not allowed to create protected branches' do
+ before do
+ allow(user_access)
+ .to receive(:can_merge_to_branch?)
+ .with('feature')
+ .and_return(false)
+ end
+
+ it 'raises an error' do
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to create protected branches on this project.')
+ end
+ end
+
+ context 'user is allowed to create protected branches' do
+ before do
+ allow(user_access)
+ .to receive(:can_merge_to_branch?)
+ .with('feature')
+ .and_return(true)
+
+ allow(project.repository)
+ .to receive(:branch_names_contains_sha)
+ .with(newrev)
+ .and_return(['branch'])
+ end
+
+ context "newrev isn't in any protected branches" do
+ before do
+ allow(ProtectedBranch)
+ .to receive(:any_protected?)
+ .with(project, ['branch'])
+ .and_return(false)
+ end
+
+ it 'raises an error' do
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only use an existing protected branch ref as the basis of a new protected branch.')
+ end
+ end
+
+ context 'newrev is included in a protected branch' do
+ before do
+ allow(ProtectedBranch)
+ .to receive(:any_protected?)
+ .with(project, ['branch'])
+ .and_return(true)
+ end
+
+ context 'via web interface' do
+ let(:protocol) { 'web' }
+
+ it 'allows branch creation' do
+ expect { subject.validate! }.not_to raise_error
+ end
+ end
+
+ context 'via SSH' do
+ it 'raises an error' do
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only create protected branches using the web interface and API.')
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/build/policy/changes_spec.rb b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
index dc3329061d1..92cf0376c02 100644
--- a/spec/lib/gitlab/ci/build/policy/changes_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/changes_spec.rb
@@ -133,7 +133,7 @@ describe Gitlab::Ci::Build::Policy::Changes do
let(:seed) { double('build seed', to_resource: ci_build) }
context 'when source is merge request' do
- let(:source) { :merge_request }
+ let(:source) { :merge_request_event }
let(:merge_request) do
create(:merge_request,
diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb
index 553fc0fb9bf..b4ddbf89b70 100644
--- a/spec/lib/gitlab/ci/build/policy/refs_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb
@@ -68,6 +68,20 @@ describe Gitlab::Ci::Build::Policy::Refs do
expect(described_class.new(%w[triggers]))
.not_to be_satisfied_by(pipeline)
end
+
+ context 'when source is merge_request_event' do
+ let(:pipeline) { build_stubbed(:ci_pipeline, source: :merge_request_event) }
+
+ it 'is satisfied with only: merge_request' do
+ expect(described_class.new(%w[merge_requests]))
+ .to be_satisfied_by(pipeline)
+ end
+
+ it 'is not satisfied with only: merge_request_event' do
+ expect(described_class.new(%w[merge_request_events]))
+ .not_to be_satisfied_by(pipeline)
+ end
+ end
end
context 'when matching a ref by a regular expression' do
diff --git a/spec/lib/gitlab/ci/build/policy/variables_spec.rb b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
index c2c0742efc3..9b016901a20 100644
--- a/spec/lib/gitlab/ci/build/policy/variables_spec.rb
+++ b/spec/lib/gitlab/ci/build/policy/variables_spec.rb
@@ -15,6 +15,7 @@ describe Gitlab::Ci::Build::Policy::Variables do
before do
pipeline.variables.build(key: 'CI_PROJECT_NAME', value: '')
+ pipeline.variables.build(key: 'MY_VARIABLE', value: 'my-var')
end
describe '#satisfied_by?' do
@@ -24,6 +25,12 @@ describe Gitlab::Ci::Build::Policy::Variables do
expect(policy).to be_satisfied_by(pipeline, seed)
end
+ it 'is satisfied by a matching pipeline variable' do
+ policy = described_class.new(['$MY_VARIABLE'])
+
+ expect(policy).to be_satisfied_by(pipeline, seed)
+ end
+
it 'is not satisfied by an overridden empty variable' do
policy = described_class.new(['$CI_PROJECT_NAME'])
@@ -68,5 +75,19 @@ describe Gitlab::Ci::Build::Policy::Variables do
expect(pipeline).not_to be_persisted
expect(seed.to_resource).not_to be_persisted
end
+
+ context 'when a bridge job is used' do
+ let(:bridge) do
+ build(:ci_bridge, pipeline: pipeline, project: project, ref: 'master')
+ end
+
+ let(:seed) { double('bridge seed', to_resource: bridge) }
+
+ it 'is satisfied by a matching expression for a bridge job' do
+ policy = described_class.new(['$MY_VARIABLE'])
+
+ expect(policy).to be_satisfied_by(pipeline, seed)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
index 1a6b3587599..fa39b32d7ab 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
describe Gitlab::Ci::Config::External::File::Base do
- let(:context) { described_class::Context.new(nil, 'HEAD', nil) }
+ let(:context) { described_class::Context.new(nil, 'HEAD', nil, Set.new) }
let(:test_class) do
Class.new(described_class) do
@@ -79,4 +79,20 @@ describe Gitlab::Ci::Config::External::File::Base do
end
end
end
+
+ describe '#to_hash' do
+ context 'with includes' do
+ let(:location) { 'some/file/config.yml' }
+ let(:content) { 'include: { template: Bash.gitlab-ci.yml }'}
+
+ before do
+ allow_any_instance_of(test_class)
+ .to receive(:content).and_return(content)
+ end
+
+ it 'does expand hash to include the template' do
+ expect(subject.to_hash).to include(:before_script)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index ff67a765da0..dc14b07287e 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -4,8 +4,10 @@ require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Local do
set(:project) { create(:project, :repository) }
+ set(:user) { create(:user) }
- let(:context) { described_class::Context.new(project, '12345', nil) }
+ let(:sha) { '12345' }
+ let(:context) { described_class::Context.new(project, sha, user, Set.new) }
let(:params) { { local: location } }
let(:local_file) { described_class.new(params, context) }
@@ -103,4 +105,36 @@ describe Gitlab::Ci::Config::External::File::Local do
expect(local_file.error_message).to eq("Local file `#{location}` does not exist!")
end
end
+
+ describe '#expand_context' do
+ let(:location) { 'location.yml' }
+
+ subject { local_file.send(:expand_context) }
+
+ it 'inherits project, user and sha' do
+ is_expected.to include(user: user, project: project, sha: sha)
+ end
+ end
+
+ describe '#to_hash' do
+ context 'properly includes another local file in the same repository' do
+ let(:location) { 'some/file/config.yml' }
+ let(:content) { 'include: { local: another-config.yml }'}
+
+ let(:another_location) { 'another-config.yml' }
+ let(:another_content) { 'rspec: JOB' }
+
+ before do
+ allow(project.repository).to receive(:blob_data_at).with(sha, location)
+ .and_return(content)
+
+ allow(project.repository).to receive(:blob_data_at).with(sha, another_location)
+ .and_return(another_content)
+ end
+
+ it 'does expand hash to include the template' do
+ expect(local_file.to_hash).to include(:rspec)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/project_spec.rb b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
index 11809adcaf6..6e89bb1b30f 100644
--- a/spec/lib/gitlab/ci/config/external/file/project_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/project_spec.rb
@@ -3,12 +3,13 @@
require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Project do
+ set(:context_project) { create(:project) }
set(:project) { create(:project, :repository) }
set(:user) { create(:user) }
let(:context_user) { user }
- let(:context) { described_class::Context.new(nil, '12345', context_user) }
- let(:subject) { described_class.new(params, context) }
+ let(:context) { described_class::Context.new(context_project, '12345', context_user, Set.new) }
+ let(:project_file) { described_class.new(params, context) }
before do
project.add_developer(user)
@@ -19,7 +20,7 @@ describe Gitlab::Ci::Config::External::File::Project do
let(:params) { { file: 'file.yml', project: 'project' } }
it 'should return true' do
- expect(subject).to be_matching
+ expect(project_file).to be_matching
end
end
@@ -27,7 +28,7 @@ describe Gitlab::Ci::Config::External::File::Project do
let(:params) { { file: 'file.yml' } }
it 'should return false' do
- expect(subject).not_to be_matching
+ expect(project_file).not_to be_matching
end
end
@@ -35,7 +36,7 @@ describe Gitlab::Ci::Config::External::File::Project do
let(:params) { { project: 'project' } }
it 'should return false' do
- expect(subject).not_to be_matching
+ expect(project_file).not_to be_matching
end
end
@@ -43,7 +44,7 @@ describe Gitlab::Ci::Config::External::File::Project do
let(:params) { {} }
it 'should return false' do
- expect(subject).not_to be_matching
+ expect(project_file).not_to be_matching
end
end
end
@@ -61,15 +62,15 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return true' do
- expect(subject).to be_valid
+ expect(project_file).to be_valid
end
context 'when user does not have permission to access file' do
let(:context_user) { create(:user) }
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include("Project `#{project.full_path}` not found or access denied!")
+ expect(project_file).not_to be_valid
+ expect(project_file.error_message).to include("Project `#{project.full_path}` not found or access denied!")
end
end
end
@@ -86,7 +87,7 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return true' do
- expect(subject).to be_valid
+ expect(project_file).to be_valid
end
end
@@ -102,8 +103,8 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!")
+ expect(project_file).not_to be_valid
+ expect(project_file.error_message).to include("Project `#{project.full_path}` file `/file.yml` is empty!")
end
end
@@ -113,8 +114,8 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!")
+ expect(project_file).not_to be_valid
+ expect(project_file.error_message).to include("Project `#{project.full_path}` reference `I-Do-Not-Exist` does not exist!")
end
end
@@ -124,8 +125,8 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!")
+ expect(project_file).not_to be_valid
+ expect(project_file.error_message).to include("Project `#{project.full_path}` file `/invalid-file.yml` does not exist!")
end
end
@@ -135,12 +136,22 @@ describe Gitlab::Ci::Config::External::File::Project do
end
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include('Included file `/invalid-file` does not have YAML extension!')
+ expect(project_file).not_to be_valid
+ expect(project_file.error_message).to include('Included file `/invalid-file` does not have YAML extension!')
end
end
end
+ describe '#expand_context' do
+ let(:params) { { file: 'file.yml', project: project.full_path, ref: 'master' } }
+
+ subject { project_file.send(:expand_context) }
+
+ it 'inherits user, and target project and sha' do
+ is_expected.to include(user: user, project: project, sha: project.commit('master').id)
+ end
+ end
+
private
def stub_project_blob(ref, path)
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index 3e0fda9c308..c5b32c29759 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Remote do
- let(:context) { described_class::Context.new(nil, '12345', nil) }
+ let(:context) { described_class::Context.new(nil, '12345', nil, Set.new) }
let(:params) { { remote: location } }
let(:remote_file) { described_class.new(params, context) }
let(:location) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
@@ -181,4 +181,14 @@ describe Gitlab::Ci::Config::External::File::Remote do
end
end
end
+
+ describe '#expand_context' do
+ let(:params) { { remote: 'http://remote' } }
+
+ subject { remote_file.send(:expand_context) }
+
+ it 'drops all parameters' do
+ is_expected.to include(user: nil, project: nil, sha: nil)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/template_spec.rb b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
index 1fb5655309a..8ecaf4800f8 100644
--- a/spec/lib/gitlab/ci/config/external/file/template_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/template_spec.rb
@@ -3,18 +3,21 @@
require 'spec_helper'
describe Gitlab::Ci::Config::External::File::Template do
- let(:context) { described_class::Context.new(nil, '12345') }
+ set(:project) { create(:project) }
+ set(:user) { create(:user) }
+
+ let(:context) { described_class::Context.new(project, '12345', user, Set.new) }
let(:template) { 'Auto-DevOps.gitlab-ci.yml' }
let(:params) { { template: template } }
- subject { described_class.new(params, context) }
+ let(:template_file) { described_class.new(params, context) }
describe '#matching?' do
context 'when a template is specified' do
let(:params) { { template: 'some-template' } }
it 'should return true' do
- expect(subject).to be_matching
+ expect(template_file).to be_matching
end
end
@@ -22,7 +25,7 @@ describe Gitlab::Ci::Config::External::File::Template do
let(:params) { { template: nil } }
it 'should return false' do
- expect(subject).not_to be_matching
+ expect(template_file).not_to be_matching
end
end
@@ -30,7 +33,7 @@ describe Gitlab::Ci::Config::External::File::Template do
let(:params) { {} }
it 'should return false' do
- expect(subject).not_to be_matching
+ expect(template_file).not_to be_matching
end
end
end
@@ -40,7 +43,7 @@ describe Gitlab::Ci::Config::External::File::Template do
let(:template) { 'Auto-DevOps.gitlab-ci.yml' }
it 'should return true' do
- expect(subject).to be_valid
+ expect(template_file).to be_valid
end
end
@@ -48,8 +51,8 @@ describe Gitlab::Ci::Config::External::File::Template do
let(:template) { 'Template.yml' }
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include('Template file `Template.yml` is not a valid location!')
+ expect(template_file).not_to be_valid
+ expect(template_file.error_message).to include('Template file `Template.yml` is not a valid location!')
end
end
@@ -57,14 +60,14 @@ describe Gitlab::Ci::Config::External::File::Template do
let(:template) { 'I-Do-Not-Have-This-Template.gitlab-ci.yml' }
it 'should return false' do
- expect(subject).not_to be_valid
- expect(subject.error_message).to include('Included file `I-Do-Not-Have-This-Template.gitlab-ci.yml` is empty or does not exist!')
+ expect(template_file).not_to be_valid
+ expect(template_file.error_message).to include('Included file `I-Do-Not-Have-This-Template.gitlab-ci.yml` is empty or does not exist!')
end
end
end
describe '#template_name' do
- let(:template_name) { subject.send(:template_name) }
+ let(:template_name) { template_file.send(:template_name) }
context 'when template does end with .gitlab-ci.yml' do
let(:template) { 'my-template.gitlab-ci.yml' }
@@ -90,4 +93,14 @@ describe Gitlab::Ci::Config::External::File::Template do
end
end
end
+
+ describe '#expand_context' do
+ let(:location) { 'location.yml' }
+
+ subject { template_file.send(:expand_context) }
+
+ it 'drops all parameters' do
+ is_expected.to include(user: nil, project: nil, sha: nil)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index 4cab4961b0f..136974569de 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -9,6 +9,7 @@ describe Gitlab::Ci::Config::External::Mapper do
let(:local_file) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
let(:remote_url) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
let(:template_file) { 'Auto-DevOps.gitlab-ci.yml' }
+ let(:expandset) { Set.new }
let(:file_content) do
<<~HEREDOC
@@ -21,7 +22,7 @@ describe Gitlab::Ci::Config::External::Mapper do
end
describe '#process' do
- subject { described_class.new(values, project: project, sha: '123456', user: user).process }
+ subject { described_class.new(values, project: project, sha: '123456', user: user, expandset: expandset).process }
context "when single 'include' keyword is defined" do
context 'when the string is a local file' do
@@ -141,5 +142,37 @@ describe Gitlab::Ci::Config::External::Mapper do
expect(subject).to be_empty
end
end
+
+ context "when duplicate 'include' is defined" do
+ let(:values) do
+ { include: [
+ { 'local' => local_file },
+ { 'local' => local_file }
+ ],
+ image: 'ruby:2.2' }
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(described_class::DuplicateIncludesError)
+ end
+ end
+
+ context "when too many 'includes' are defined" do
+ let(:values) do
+ { include: [
+ { 'local' => local_file },
+ { 'remote' => remote_url }
+ ],
+ image: 'ruby:2.2' }
+ end
+
+ before do
+ stub_const("#{described_class}::MAX_INCLUDES", 1)
+ end
+
+ it 'raises an exception' do
+ expect { subject }.to raise_error(described_class::TooManyIncludesError)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 1ac58139b25..3f6f6d7c5d9 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -4,15 +4,20 @@ require 'spec_helper'
describe Gitlab::Ci::Config::External::Processor do
set(:project) { create(:project, :repository) }
+ set(:another_project) { create(:project, :repository) }
set(:user) { create(:user) }
- let(:processor) { described_class.new(values, project: project, sha: '12345', user: user) }
+ let(:expandset) { Set.new }
+ let(:sha) { '12345' }
+ let(:processor) { described_class.new(values, project: project, sha: '12345', user: user, expandset: expandset) }
before do
project.add_developer(user)
end
describe "#perform" do
+ subject { processor.perform }
+
context 'when no external files defined' do
let(:values) { { image: 'ruby:2.2' } }
@@ -190,5 +195,80 @@ describe Gitlab::Ci::Config::External::Processor do
expect(processor.perform[:image]).to eq('ruby:2.2')
end
end
+
+ context "when a nested includes are defined" do
+ let(:values) do
+ {
+ include: [
+ { local: '/local/file.yml' }
+ ],
+ image: 'ruby:2.2'
+ }
+ end
+
+ before do
+ allow(project.repository).to receive(:blob_data_at).with('12345', '/local/file.yml') do
+ <<~HEREDOC
+ include:
+ - template: Ruby.gitlab-ci.yml
+ - remote: http://my.domain.com/config.yml
+ - project: #{another_project.full_path}
+ file: /templates/my-workflow.yml
+ HEREDOC
+ end
+
+ allow_any_instance_of(Repository).to receive(:blob_data_at).with(another_project.commit.id, '/templates/my-workflow.yml') do
+ <<~HEREDOC
+ include:
+ - local: /templates/my-build.yml
+ HEREDOC
+ end
+
+ allow_any_instance_of(Repository).to receive(:blob_data_at).with(another_project.commit.id, '/templates/my-build.yml') do
+ <<~HEREDOC
+ my_build:
+ script: echo Hello World
+ HEREDOC
+ end
+
+ WebMock.stub_request(:get, 'http://my.domain.com/config.yml').to_return(body: 'remote_build: { script: echo Hello World }')
+ end
+
+ context 'when project is public' do
+ before do
+ another_project.update!(visibility: 'public')
+ end
+
+ it 'properly expands all includes' do
+ is_expected.to include(:my_build, :remote_build, :rspec)
+ end
+ end
+
+ context 'when user is reporter of another project' do
+ before do
+ another_project.add_reporter(user)
+ end
+
+ it 'properly expands all includes' do
+ is_expected.to include(:my_build, :remote_build, :rspec)
+ end
+ end
+
+ context 'when user is not allowed' do
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError, /not found or access denied/)
+ end
+ end
+
+ context 'when too many includes is included' do
+ before do
+ stub_const('Gitlab::Ci::Config::External::Mapper::MAX_INCLUDES', 1)
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError, /Maximum of 1 nested/)
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
index c9d1d09a938..3debd42ac65 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb
@@ -96,7 +96,7 @@ describe Gitlab::Ci::Pipeline::Chain::Build do
context 'when pipeline is running for a merge request' do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
- source: :merge_request,
+ source: :merge_request_event,
origin_ref: 'feature',
checkout_sha: project.commit.id,
after_sha: nil,
@@ -117,7 +117,7 @@ describe Gitlab::Ci::Pipeline::Chain::Build do
end
it 'correctly indicated that this is a merge request pipeline' do
- expect(pipeline).to be_merge_request
+ expect(pipeline).to be_merge_request_event
expect(pipeline.merge_request).to eq(merge_request)
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
index 053bc421649..e6c6a82b463 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
@@ -115,7 +115,7 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do
let(:pipeline) { build_stubbed(:ci_pipeline, project: project) }
let(:merge_request_pipeline) do
- build(:ci_pipeline, source: :merge_request, project: project)
+ build(:ci_pipeline, source: :merge_request_event, project: project)
end
let(:chain) { described_class.new(merge_request_pipeline, command).tap(&:perform!) }
diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb
index 0dd74399a47..fbbd58280a9 100644
--- a/spec/lib/gitlab/ci/templates/templates_spec.rb
+++ b/spec/lib/gitlab/ci/templates/templates_spec.rb
@@ -3,9 +3,40 @@
require 'spec_helper'
describe "CI YML Templates" do
- Gitlab::Template::GitlabCiYmlTemplate.all.each do |template|
- it "#{template.name} should be valid" do
- expect { Gitlab::Ci::YamlProcessor.new(template.content) }.not_to raise_error
+ ABSTRACT_TEMPLATES = %w[Serverless].freeze
+
+ def self.concrete_templates
+ Gitlab::Template::GitlabCiYmlTemplate.all.reject do |template|
+ ABSTRACT_TEMPLATES.include?(template.name)
+ end
+ end
+
+ def self.abstract_templates
+ Gitlab::Template::GitlabCiYmlTemplate.all.select do |template|
+ ABSTRACT_TEMPLATES.include?(template.name)
+ end
+ end
+
+ describe 'concrete templates with CI/CD jobs' do
+ concrete_templates.each do |template|
+ it "#{template.name} template should be valid" do
+ expect { Gitlab::Ci::YamlProcessor.new(template.content) }
+ .not_to raise_error
+ end
+ end
+ end
+
+ describe 'abstract templates without concrete jobs defined' do
+ abstract_templates.each do |template|
+ it "#{template.name} template should be valid after being implemented" do
+ content = template.content + <<~EOS
+ concrete_build_implemented_by_a_user:
+ stage: build
+ script: do something
+ EOS
+
+ expect { Gitlab::Ci::YamlProcessor.new(content) }.not_to raise_error
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
index 8bf44acb228..3ff2fe18c15 100644
--- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Variables::Collection::Item do
let(:expected_value) { variable_value }
let(:variable) do
- { key: variable_key, value: variable_value, public: true }
+ { key: variable_key, value: variable_value, public: true, masked: false }
end
describe '.new' do
@@ -88,7 +88,7 @@ describe Gitlab::Ci::Variables::Collection::Item do
resource = described_class.fabricate(variable)
expect(resource).to be_a(described_class)
- expect(resource).to eq(key: 'CI_VAR', value: '123', public: false)
+ expect(resource).to eq(key: 'CI_VAR', value: '123', public: false, masked: false)
end
it 'supports using another collection item' do
@@ -134,7 +134,21 @@ describe Gitlab::Ci::Variables::Collection::Item do
.to_runner_variable
expect(runner_variable)
- .to eq(key: 'VAR', value: 'value', public: true, file: true)
+ .to eq(key: 'VAR', value: 'value', public: true, file: true, masked: false)
+ end
+ end
+
+ context 'when variable masking is disabled' do
+ before do
+ stub_feature_flags(variable_masking: false)
+ end
+
+ it 'does not expose the masked field to the runner' do
+ runner_variable = described_class
+ .new(key: 'VAR', value: 'value', masked: true)
+ .to_runner_variable
+
+ expect(runner_variable).to eq(key: 'VAR', value: 'value', public: true)
end
end
end
diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb
index 5c91816a586..8e732d44d5d 100644
--- a/spec/lib/gitlab/ci/variables/collection_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Ci::Variables::Collection do
describe '.new' do
it 'can be initialized with an array' do
- variable = { key: 'VAR', value: 'value', public: true }
+ variable = { key: 'VAR', value: 'value', public: true, masked: false }
collection = described_class.new([variable])
@@ -66,6 +66,14 @@ describe Gitlab::Ci::Variables::Collection do
expect(collection).to include(key: 'VAR_3', value: '3', public: true)
end
+ it 'does not concatenate resource if it undefined' do
+ collection = described_class.new([{ key: 'VAR_1', value: '1' }])
+
+ collection.concat(nil)
+
+ expect(collection).to be_one
+ end
+
it 'returns self' do
expect(subject.concat([key: 'VAR', value: 'test']))
.to eq subject
@@ -93,7 +101,7 @@ describe Gitlab::Ci::Variables::Collection do
collection = described_class.new([{ key: 'TEST', value: '1' }])
expect(collection.to_runner_variables)
- .to eq [{ key: 'TEST', value: '1', public: true }]
+ .to eq [{ key: 'TEST', value: '1', public: true, masked: false }]
end
end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index caf9fc5442c..17d5eae24f5 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -143,7 +143,7 @@ describe Gitlab::CurrentSettings do
it_behaves_like 'a non-persisted ApplicationSetting object'
- it 'uses the value from the DB attribute if present and not overriden by an accessor' do
+ it 'uses the value from the DB attribute if present and not overridden by an accessor' do
expect(current_settings.home_page_url).to eq(db_settings.home_page_url)
end
end
diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb
index 00cb1e6446a..66cd8171c12 100644
--- a/spec/lib/gitlab/danger/helper_spec.rb
+++ b/spec/lib/gitlab/danger/helper_spec.rb
@@ -265,6 +265,7 @@ describe Gitlab::Danger::Helper do
'changelogs/foo' | :none
'ee/changelogs/foo' | :none
+ 'locale/gitlab.pot' | :none
'FOO' | :unknown
'foo' | :unknown
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
index 248cca25a2c..81419e51635 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
@@ -19,7 +19,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :delete
Project.find(project.id)
end
- describe "#remove_last_ocurrence" do
+ describe "#remove_last_occurrence" do
it "removes only the last occurrence of a string" do
input = "this/is/a-word-to-replace/namespace/with/a-word-to-replace"
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
index 4d222564fd0..0ebd8994636 100644
--- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -50,8 +50,8 @@ describe Gitlab::DependencyLinker::ComposerJsonLinker do
%{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
end
- it 'links the module name' do
- expect(subject).to include(link('laravel/laravel', 'https://packagist.org/packages/laravel/laravel'))
+ it 'does not link the module name' do
+ expect(subject).not_to include(link('laravel/laravel', 'https://packagist.org/packages/laravel/laravel'))
end
it 'links the homepage' do
diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
index a97803b119e..f00f6b47b94 100644
--- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
@@ -41,13 +41,16 @@ describe Gitlab::DependencyLinker::GemfileLinker do
end
it 'links dependencies' do
- expect(subject).to include(link('rails', 'https://rubygems.org/gems/rails'))
expect(subject).to include(link('rails-deprecated_sanitizer', 'https://rubygems.org/gems/rails-deprecated_sanitizer'))
- expect(subject).to include(link('responders', 'https://rubygems.org/gems/responders'))
- expect(subject).to include(link('sprockets', 'https://rubygems.org/gems/sprockets'))
expect(subject).to include(link('default_value_for', 'https://rubygems.org/gems/default_value_for'))
end
+ it 'links to external dependencies' do
+ expect(subject).to include(link('rails', 'https://github.com/rails/rails'))
+ expect(subject).to include(link('responders', 'https://github.com/rails/responders'))
+ expect(subject).to include(link('sprockets', 'https://gitlab.example.com/gems/sprockets'))
+ end
+
it 'links GitHub repos' do
expect(subject).to include(link('rails/rails', 'https://github.com/rails/rails'))
expect(subject).to include(link('rails/responders', 'https://github.com/rails/responders'))
diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
index 24ad7d12f4c..6c6a5d70576 100644
--- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
@@ -43,8 +43,8 @@ describe Gitlab::DependencyLinker::GemspecLinker do
%{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
end
- it 'links the gem name' do
- expect(subject).to include(link('gitlab_git', 'https://rubygems.org/gems/gitlab_git'))
+ it 'does not link the gem name' do
+ expect(subject).not_to include(link('gitlab_git', 'https://rubygems.org/gems/gitlab_git'))
end
it 'links the license' do
diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
index 1e8b72afb7b..9050127af7f 100644
--- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
@@ -33,7 +33,8 @@ describe Gitlab::DependencyLinker::PackageJsonLinker do
"express": "4.2.x",
"bigpipe": "bigpipe/pagelet",
"plates": "https://github.com/flatiron/plates/tarball/master",
- "karma": "^1.4.1"
+ "karma": "^1.4.1",
+ "random": "git+https://EdOverflow@github.com/example/example.git"
},
"devDependencies": {
"vows": "^0.7.0",
@@ -51,8 +52,8 @@ describe Gitlab::DependencyLinker::PackageJsonLinker do
%{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
end
- it 'links the module name' do
- expect(subject).to include(link('module-name', 'https://npmjs.com/package/module-name'))
+ it 'does not link the module name' do
+ expect(subject).not_to include(link('module-name', 'https://npmjs.com/package/module-name'))
end
it 'links the homepage' do
@@ -71,14 +72,21 @@ describe Gitlab::DependencyLinker::PackageJsonLinker do
expect(subject).to include(link('primus', 'https://npmjs.com/package/primus'))
expect(subject).to include(link('async', 'https://npmjs.com/package/async'))
expect(subject).to include(link('express', 'https://npmjs.com/package/express'))
- expect(subject).to include(link('bigpipe', 'https://npmjs.com/package/bigpipe'))
- expect(subject).to include(link('plates', 'https://npmjs.com/package/plates'))
expect(subject).to include(link('karma', 'https://npmjs.com/package/karma'))
expect(subject).to include(link('vows', 'https://npmjs.com/package/vows'))
expect(subject).to include(link('assume', 'https://npmjs.com/package/assume'))
expect(subject).to include(link('pre-commit', 'https://npmjs.com/package/pre-commit'))
end
+ it 'links dependencies to URL detected on value' do
+ expect(subject).to include(link('bigpipe', 'https://github.com/bigpipe/pagelet'))
+ expect(subject).to include(link('plates', 'https://github.com/flatiron/plates/tarball/master'))
+ end
+
+ it 'does not link to NPM when invalid git URL' do
+ expect(subject).not_to include(link('random', 'https://npmjs.com/package/random'))
+ end
+
it 'links GitHub repos' do
expect(subject).to include(link('bigpipe/pagelet', 'https://github.com/bigpipe/pagelet'))
end
diff --git a/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb
new file mode 100644
index 00000000000..9bfb1b13a2b
--- /dev/null
+++ b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Gitlab::DependencyLinker::Parser::Gemfile do
+ describe '#parse' do
+ let(:file_content) do
+ <<-CONTENT.strip_heredoc
+ source 'https://rubygems.org'
+
+ gem "rails", '4.2.6', github: "rails/rails"
+ gem 'rails-deprecated_sanitizer', '~> 1.0.3'
+ gem 'responders', '~> 2.0', :github => 'rails/responders'
+ gem 'sprockets', '~> 3.6.0', git: 'https://gitlab.example.com/gems/sprockets'
+ gem 'default_value_for', '~> 3.0.0'
+ CONTENT
+ end
+
+ subject { described_class.new(file_content).parse(keyword: 'gem') }
+
+ def fetch_package(name)
+ subject.find { |package| package.name == name }
+ end
+
+ it 'returns parsed packages' do
+ expect(subject.size).to eq(5)
+ expect(subject).to all(be_a(Gitlab::DependencyLinker::Package))
+ end
+
+ it 'packages respond to name and external_ref accordingly' do
+ expect(fetch_package('rails')).to have_attributes(name: 'rails',
+ github_ref: 'rails/rails',
+ git_ref: nil)
+
+ expect(fetch_package('sprockets')).to have_attributes(name: 'sprockets',
+ github_ref: nil,
+ git_ref: 'https://gitlab.example.com/gems/sprockets')
+
+ expect(fetch_package('default_value_for')).to have_attributes(name: 'default_value_for',
+ github_ref: nil,
+ git_ref: nil)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
index cdfd7ad9826..8f1b523653e 100644
--- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
@@ -43,7 +43,10 @@ describe Gitlab::DependencyLinker::PodfileLinker do
it 'links packages' do
expect(subject).to include(link('AFNetworking', 'https://cocoapods.org/pods/AFNetworking'))
- expect(subject).to include(link('Interstellar/Core', 'https://cocoapods.org/pods/Interstellar'))
+ end
+
+ it 'links external packages' do
+ expect(subject).to include(link('Interstellar/Core', 'https://github.com/ashfurrow/Interstellar.git'))
end
it 'links Git repos' do
diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
index ed60ab45955..bacec830103 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
@@ -42,8 +42,8 @@ describe Gitlab::DependencyLinker::PodspecLinker do
%{<a href="#{url}" rel="nofollow noreferrer noopener" target="_blank">#{name}</a>}
end
- it 'links the gem name' do
- expect(subject).to include(link('Reachability', 'https://cocoapods.org/pods/Reachability'))
+ it 'does not link the pod name' do
+ expect(subject).not_to include(link('Reachability', 'https://cocoapods.org/pods/Reachability'))
end
it 'links the license' do
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 862590268ca..611c3e946ed 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -8,6 +8,47 @@ describe Gitlab::Diff::File do
let(:diff) { commit.raw_diffs.first }
let(:diff_file) { described_class.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
+ def create_file(file_name, content)
+ Files::CreateService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
+ def update_file(file_name, content)
+ Files::UpdateService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
+ def delete_file(file_name)
+ Files::DeleteService.new(
+ project,
+ project.owner,
+ commit_message: 'Update',
+ start_branch: branch_name,
+ branch_name: branch_name,
+ file_path: file_name
+ ).execute
+
+ project.commit(branch_name).diffs.diff_files.first
+ end
+
describe '#diff_lines' do
let(:diff_lines) { diff_file.diff_lines }
@@ -675,47 +716,6 @@ describe Gitlab::Diff::File do
end
let(:branch_name) { 'master' }
- def create_file(file_name, content)
- Files::CreateService.new(
- project,
- project.owner,
- commit_message: 'Update',
- start_branch: branch_name,
- branch_name: branch_name,
- file_path: file_name,
- file_content: content
- ).execute
-
- project.commit(branch_name).diffs.diff_files.first
- end
-
- def update_file(file_name, content)
- Files::UpdateService.new(
- project,
- project.owner,
- commit_message: 'Update',
- start_branch: branch_name,
- branch_name: branch_name,
- file_path: file_name,
- file_content: content
- ).execute
-
- project.commit(branch_name).diffs.diff_files.first
- end
-
- def delete_file(file_name)
- Files::DeleteService.new(
- project,
- project.owner,
- commit_message: 'Update',
- start_branch: branch_name,
- branch_name: branch_name,
- file_path: file_name
- ).execute
-
- project.commit(branch_name).diffs.diff_files.first
- end
-
context 'when empty file is created' do
it 'returns true' do
diff_file = create_file('empty.md', '')
@@ -751,4 +751,123 @@ describe Gitlab::Diff::File do
end
end
end
+
+ describe '#fully_expanded?' do
+ let(:project) do
+ create(:project, :custom_repo, files: {})
+ end
+ let(:branch_name) { 'master' }
+
+ context 'when empty file is created' do
+ it 'returns true' do
+ diff_file = create_file('empty.md', '')
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when empty file is deleted' do
+ it 'returns true' do
+ create_file('empty.md', '')
+ diff_file = delete_file('empty.md')
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when short file with last line removed' do
+ it 'returns true' do
+ create_file('with-content.md', (1..3).to_a.join("\n"))
+ diff_file = update_file('with-content.md', (1..2).to_a.join("\n"))
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when a single line is added to empty file' do
+ it 'returns true' do
+ create_file('empty.md', '')
+ diff_file = update_file('empty.md', 'new content')
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when single line file is changed' do
+ it 'returns true' do
+ create_file('file.md', 'foo')
+ diff_file = update_file('file.md', 'bar')
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when long file is changed' do
+ before do
+ create_file('file.md', (1..999).to_a.join("\n"))
+ end
+
+ context 'when first line is removed' do
+ it 'returns true' do
+ diff_file = update_file('file.md', (2..999).to_a.join("\n"))
+
+ expect(diff_file.fully_expanded?).to be_falsey
+ end
+ end
+
+ context 'when last line is removed' do
+ it 'returns true' do
+ diff_file = update_file('file.md', (1..998).to_a.join("\n"))
+
+ expect(diff_file.fully_expanded?).to be_falsey
+ end
+ end
+
+ context 'when first and last lines are removed' do
+ it 'returns false' do
+ diff_file = update_file('file.md', (2..998).to_a.join("\n"))
+
+ expect(diff_file.fully_expanded?).to be_falsey
+ end
+ end
+
+ context 'when first and last lines are changed' do
+ it 'returns false' do
+ content = (2..998).to_a
+ content.prepend('a')
+ content.append('z')
+ content = content.join("\n")
+
+ diff_file = update_file('file.md', content)
+
+ expect(diff_file.fully_expanded?).to be_falsey
+ end
+ end
+
+ context 'when every line are changed' do
+ it 'returns true' do
+ diff_file = update_file('file.md', "hi\n" * 999)
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when all contents are cleared' do
+ it 'returns true' do
+ diff_file = update_file('file.md', "")
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+
+ context 'when file is binary' do
+ it 'returns true' do
+ diff_file = update_file('file.md', (1..998).to_a.join("\n"))
+ allow(diff_file).to receive(:binary?).and_return(true)
+
+ expect(diff_file.fully_expanded?).to be_truthy
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index a1b5cea88c0..10bc82e24d1 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
- describe '.find' do
+ shared_examples '.find' do
context 'nil path' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, nil) }
@@ -128,6 +128,20 @@ describe Gitlab::Git::Blob, :seed_helper do
end
end
+ describe '.find with Gitaly enabled' do
+ it_behaves_like '.find'
+ end
+
+ describe '.find with Rugged enabled', :enable_rugged do
+ it 'calls out to the Rugged implementation' do
+ allow_any_instance_of(Rugged).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
+
+ described_class.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg')
+ end
+
+ it_behaves_like '.find'
+ end
+
describe '.raw' do
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 2611ebed25b..3fb41a626b2 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -112,7 +112,7 @@ describe Gitlab::Git::Commit, :seed_helper do
end
context 'Class methods' do
- describe '.find' do
+ shared_examples '.find' do
it "should return first head commit if without params" do
expect(described_class.last(repository).id).to eq(
rugged_repo.head.target.oid
@@ -154,6 +154,20 @@ describe Gitlab::Git::Commit, :seed_helper do
end
end
+ describe '.find with Gitaly enabled' do
+ it_should_behave_like '.find'
+ end
+
+ describe '.find with Rugged enabled', :enable_rugged do
+ it 'calls out to the Rugged implementation' do
+ allow_any_instance_of(Rugged).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
+
+ described_class.find(repository, SeedRepo::Commit::ID)
+ end
+
+ it_should_behave_like '.find'
+ end
+
describe '.last_for_path' do
context 'no path' do
subject { described_class.last_for_path(repository, 'master') }
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index e3dd02f1478..7e6dfa30e37 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -619,16 +619,6 @@ describe Gitlab::Git::Repository, :seed_helper do
repository.search_files_by_content('search-files-by-content', 'search-files-by-content-branch')
end
end
-
- it_should_behave_like 'search files by content' do
- let(:search_results) do
- repository.gitaly_repository_client.search_files_by_content(
- 'search-files-by-content-branch',
- 'search-files-by-content',
- chunked_response: false
- )
- end
- end
end
describe '#find_remote_root_ref' do
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 4a4d69490a3..60060c41616 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -3,7 +3,7 @@ require "spec_helper"
describe Gitlab::Git::Tree, :seed_helper do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
- context :repo do
+ shared_examples :repo do
let(:tree) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID) }
it { expect(tree).to be_kind_of Array }
@@ -12,6 +12,17 @@ describe Gitlab::Git::Tree, :seed_helper do
it { expect(tree.select(&:file?).size).to eq(10) }
it { expect(tree.select(&:submodule?).size).to eq(2) }
+ it 'returns an empty array when called with an invalid ref' do
+ expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
+ end
+
+ it 'returns a list of tree objects' do
+ entries = described_class.where(repository, SeedRepo::Commit::ID, 'files', true)
+
+ expect(entries.count).to be > 10
+ expect(entries).to all(be_a(Gitlab::Git::Tree))
+ end
+
describe '#dir?' do
let(:dir) { tree.select(&:dir?).first }
@@ -20,8 +31,8 @@ describe Gitlab::Git::Tree, :seed_helper do
it { expect(dir.commit_id).to eq(SeedRepo::Commit::ID) }
it { expect(dir.name).to eq('encoding') }
it { expect(dir.path).to eq('encoding') }
- it { expect(dir.flat_path).to eq('encoding') }
it { expect(dir.mode).to eq('40000') }
+ it { expect(dir.flat_path).to eq('encoding') }
context :subdir do
let(:subdir) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID, 'files').first }
@@ -44,6 +55,51 @@ describe Gitlab::Git::Tree, :seed_helper do
it { expect(subdir_file.path).to eq('files/ruby/popen.rb') }
it { expect(subdir_file.flat_path).to eq('files/ruby/popen.rb') }
end
+
+ context :flat_path do
+ let(:filename) { 'files/flat/path/correct/content.txt' }
+ let(:oid) { create_file(filename) }
+ let(:subdir_file) { Gitlab::Git::Tree.where(repository, oid, 'files/flat').first }
+ let(:repository_rugged) { Rugged::Repository.new(File.join(SEED_STORAGE_PATH, TEST_REPO_PATH)) }
+
+ it { expect(subdir_file.flat_path).to eq('files/flat/path/correct') }
+ end
+
+ def create_file(path)
+ oid = repository_rugged.write('test', :blob)
+ index = repository_rugged.index
+ index.add(path: filename, oid: oid, mode: 0100644)
+
+ options = commit_options(
+ repository_rugged,
+ index,
+ repository_rugged.head.target,
+ 'HEAD',
+ 'Add new file')
+
+ Rugged::Commit.create(repository_rugged, options)
+ end
+
+ # Build the options hash that's passed to Rugged::Commit#create
+ def commit_options(repo, index, target, ref, message)
+ options = {}
+ options[:tree] = index.write_tree(repo)
+ options[:author] = {
+ email: "test@example.com",
+ name: "Test Author",
+ time: Time.gm(2014, "mar", 3, 20, 15, 1)
+ }
+ options[:committer] = {
+ email: "test@example.com",
+ name: "Test Author",
+ time: Time.gm(2014, "mar", 3, 20, 15, 1)
+ }
+ options[:message] ||= message
+ options[:parents] = repo.empty? ? [] : [target].compact
+ options[:update_ref] = ref
+
+ options
+ end
end
describe '#file?' do
@@ -79,9 +135,17 @@ describe Gitlab::Git::Tree, :seed_helper do
end
end
- describe '#where' do
- it 'returns an empty array when called with an invalid ref' do
- expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([])
+ describe '.where with Gitaly enabled' do
+ it_behaves_like :repo
+ end
+
+ describe '.where with Rugged enabled', :enable_rugged do
+ it 'calls out to the Rugged implementation' do
+ allow_any_instance_of(Rugged).to receive(:lookup).with(SeedRepo::Commit::ID)
+
+ described_class.where(repository, SeedRepo::Commit::ID, 'files', false)
end
+
+ it_behaves_like :repo
end
end
diff --git a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
index c89913ec8e9..bb10be2a4dc 100644
--- a/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/storage_settings_spec.rb
@@ -26,4 +26,14 @@ describe Gitlab::GitalyClient::StorageSettings do
end
end
end
+
+ describe '.disk_access_denied?' do
+ it 'return false when Rugged is enabled', :enable_rugged do
+ expect(described_class.disk_access_denied?).to be_falsey
+ end
+
+ it 'returns true' do
+ expect(described_class.disk_access_denied?).to be_truthy
+ end
+ end
end
diff --git a/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb b/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb
index b1cac3b6e46..120a07ff2b3 100644
--- a/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/milestones_importer_spec.rb
@@ -4,6 +4,7 @@ describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis
let(:project) { create(:project, import_source: 'foo/bar') }
let(:client) { double(:client) }
let(:importer) { described_class.new(project, client) }
+ let(:due_on) { Time.new(2017, 2, 1, 12, 00) }
let(:created_at) { Time.new(2017, 1, 1, 12, 00) }
let(:updated_at) { Time.new(2017, 1, 1, 12, 15) }
@@ -14,6 +15,20 @@ describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis
title: '1.0',
description: 'The first release',
state: 'open',
+ due_on: due_on,
+ created_at: created_at,
+ updated_at: updated_at
+ )
+ end
+
+ let(:milestone2) do
+ double(
+ :milestone,
+ number: 1,
+ title: '1.0',
+ description: 'The first release',
+ state: 'open',
+ due_on: nil,
created_at: created_at,
updated_at: updated_at
)
@@ -72,6 +87,7 @@ describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis
describe '#build' do
let(:milestone_hash) { importer.build(milestone) }
+ let(:milestone_hash2) { importer.build(milestone2) }
it 'returns the attributes of the milestone as a Hash' do
expect(milestone_hash).to be_an_instance_of(Hash)
@@ -98,6 +114,14 @@ describe Gitlab::GithubImport::Importer::MilestonesImporter, :clean_gitlab_redis
expect(milestone_hash[:state]).to eq(:active)
end
+ it 'includes the due date' do
+ expect(milestone_hash[:due_date]).to eq(due_on.to_date)
+ end
+
+ it 'responds correctly to no due date value' do
+ expect(milestone_hash2[:due_date]).to be nil
+ end
+
it 'includes the created timestamp' do
expect(milestone_hash[:created_at]).to eq(created_at)
end
diff --git a/spec/lib/gitlab/hashed_storage/migrator_spec.rb b/spec/lib/gitlab/hashed_storage/migrator_spec.rb
index 3942f168ceb..6154b3e2f76 100644
--- a/spec/lib/gitlab/hashed_storage/migrator_spec.rb
+++ b/spec/lib/gitlab/hashed_storage/migrator_spec.rb
@@ -1,21 +1,29 @@
require 'spec_helper'
describe Gitlab::HashedStorage::Migrator do
- describe '#bulk_schedule' do
- it 'schedules job to StorageMigratorWorker' do
+ describe '#bulk_schedule_migration' do
+ it 'schedules job to HashedStorage::MigratorWorker' do
Sidekiq::Testing.fake! do
- expect { subject.bulk_schedule(start: 1, finish: 5) }.to change(HashedStorage::MigratorWorker.jobs, :size).by(1)
+ expect { subject.bulk_schedule_migration(start: 1, finish: 5) }.to change(HashedStorage::MigratorWorker.jobs, :size).by(1)
+ end
+ end
+ end
+
+ describe '#bulk_schedule_rollback' do
+ it 'schedules job to HashedStorage::RollbackerWorker' do
+ Sidekiq::Testing.fake! do
+ expect { subject.bulk_schedule_rollback(start: 1, finish: 5) }.to change(HashedStorage::RollbackerWorker.jobs, :size).by(1)
end
end
end
describe '#bulk_migrate' do
- let(:projects) { create_list(:project, 2, :legacy_storage) }
+ let(:projects) { create_list(:project, 2, :legacy_storage, :empty_repo) }
let(:ids) { projects.map(&:id) }
- it 'enqueue jobs to ProjectMigrateHashedStorageWorker' do
+ it 'enqueue jobs to HashedStorage::ProjectMigrateWorker' do
Sidekiq::Testing.fake! do
- expect { subject.bulk_migrate(start: ids.min, finish: ids.max) }.to change(ProjectMigrateHashedStorageWorker.jobs, :size).by(2)
+ expect { subject.bulk_migrate(start: ids.min, finish: ids.max) }.to change(HashedStorage::ProjectMigrateWorker.jobs, :size).by(2)
end
end
@@ -32,13 +40,53 @@ describe Gitlab::HashedStorage::Migrator do
subject.bulk_migrate(start: ids.min, finish: ids.max)
end
- it 'has migrated projects set as writable' do
+ it 'has all projects migrated and set as writable' do
perform_enqueued_jobs do
subject.bulk_migrate(start: ids.min, finish: ids.max)
end
projects.each do |project|
- expect(project.reload.repository_read_only?).to be_falsey
+ project.reload
+
+ expect(project.hashed_storage?(:repository)).to be_truthy
+ expect(project.repository_read_only?).to be_falsey
+ end
+ end
+ end
+
+ describe '#bulk_rollback' do
+ let(:projects) { create_list(:project, 2, :empty_repo) }
+ let(:ids) { projects.map(&:id) }
+
+ it 'enqueue jobs to HashedStorage::ProjectRollbackWorker' do
+ Sidekiq::Testing.fake! do
+ expect { subject.bulk_rollback(start: ids.min, finish: ids.max) }.to change(HashedStorage::ProjectRollbackWorker.jobs, :size).by(2)
+ end
+ end
+
+ it 'rescues and log exceptions' do
+ allow_any_instance_of(Project).to receive(:rollback_to_legacy_storage!).and_raise(StandardError)
+ expect { subject.bulk_rollback(start: ids.min, finish: ids.max) }.not_to raise_error
+ end
+
+ it 'delegates each project in specified range to #rollback' do
+ projects.each do |project|
+ expect(subject).to receive(:rollback).with(project)
+ end
+
+ subject.bulk_rollback(start: ids.min, finish: ids.max)
+ end
+
+ it 'has all projects rolledback and set as writable' do
+ perform_enqueued_jobs do
+ subject.bulk_rollback(start: ids.min, finish: ids.max)
+ end
+
+ projects.each do |project|
+ project.reload
+
+ expect(project.legacy_storage?).to be_truthy
+ expect(project.repository_read_only?).to be_falsey
end
end
end
@@ -48,7 +96,7 @@ describe Gitlab::HashedStorage::Migrator do
it 'enqueues project migration job' do
Sidekiq::Testing.fake! do
- expect { subject.migrate(project) }.to change(ProjectMigrateHashedStorageWorker.jobs, :size).by(1)
+ expect { subject.migrate(project) }.to change(HashedStorage::ProjectMigrateWorker.jobs, :size).by(1)
end
end
@@ -79,7 +127,7 @@ describe Gitlab::HashedStorage::Migrator do
it 'doesnt enqueue any migration job' do
Sidekiq::Testing.fake! do
- expect { subject.migrate(project) }.not_to change(ProjectMigrateHashedStorageWorker.jobs, :size)
+ expect { subject.migrate(project) }.not_to change(HashedStorage::ProjectMigrateWorker.jobs, :size)
end
end
@@ -88,4 +136,50 @@ describe Gitlab::HashedStorage::Migrator do
end
end
end
+
+ describe '#rollback' do
+ let(:project) { create(:project, :empty_repo) }
+
+ it 'enqueues project rollback job' do
+ Sidekiq::Testing.fake! do
+ expect { subject.rollback(project) }.to change(HashedStorage::ProjectRollbackWorker.jobs, :size).by(1)
+ end
+ end
+
+ it 'rescues and log exceptions' do
+ allow(project).to receive(:rollback_to_hashed_storage!).and_raise(StandardError)
+
+ expect { subject.rollback(project) }.not_to raise_error
+ end
+
+ it 'rolls-back project storage' do
+ perform_enqueued_jobs do
+ subject.rollback(project)
+ end
+
+ expect(project.reload.legacy_storage?).to be_truthy
+ end
+
+ it 'has rolled-back project set as writable' do
+ perform_enqueued_jobs do
+ subject.rollback(project)
+ end
+
+ expect(project.reload.repository_read_only?).to be_falsey
+ end
+
+ context 'when project is already on legacy storage' do
+ let(:project) { create(:project, :legacy_storage, :empty_repo) }
+
+ it 'doesnt enqueue any rollback job' do
+ Sidekiq::Testing.fake! do
+ expect { subject.rollback(project) }.not_to change(HashedStorage::ProjectRollbackWorker.jobs, :size)
+ end
+ end
+
+ it 'returns false' do
+ expect(subject.rollback(project)).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 018a5d3dd3d..01da3ea7081 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -127,7 +127,7 @@ ci_pipelines:
- scheduled_actions
- artifacts
- pipeline_schedule
-- merge_requests
+- merge_requests_as_head_pipeline
- merge_request
- deployments
- environments
diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
index 68eaa70e6b6..4b234411a44 100644
--- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
+++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
@@ -41,4 +41,20 @@ describe Gitlab::ImportExport::MergeRequestParser do
expect(parsed_merge_request).to eq(merge_request)
end
+
+ context 'when the merge request has diffs' do
+ let(:merge_request) do
+ build(:merge_request, source_project: forked_project, target_project: project)
+ end
+
+ context 'when the diff is invalid' do
+ let(:merge_request_diff) { build(:merge_request_diff, merge_request: merge_request, base_commit_sha: 'foobar') }
+
+ it 'sets the diff to nil' do
+ expect(merge_request_diff).to be_invalid
+ expect(merge_request_diff.merge_request).to eq merge_request
+ expect(parsed_merge_request.merge_request_diff).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb
index b52078e8556..2cae8ec031a 100644
--- a/spec/lib/gitlab/json_cache_spec.rb
+++ b/spec/lib/gitlab/json_cache_spec.rb
@@ -297,13 +297,39 @@ describe Gitlab::JsonCache do
expect(result).to eq(broadcast_message)
end
+ context 'when the cached value is an instance of ActiveRecord::Base' do
+ it 'returns a persisted record when id is set' do
+ backend.write(expanded_key, broadcast_message.to_json)
+
+ result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
+
+ expect(result).to be_persisted
+ end
+
+ it 'returns a new record when id is nil' do
+ backend.write(expanded_key, build(:broadcast_message).to_json)
+
+ result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
+
+ expect(result).to be_new_record
+ end
+
+ it 'returns a new record when id is missing' do
+ backend.write(expanded_key, build(:broadcast_message).attributes.except('id').to_json)
+
+ result = cache.fetch(key, as: BroadcastMessage) { 'block result' }
+
+ expect(result).to be_new_record
+ end
+ end
+
it "returns the result of the block when 'as' option is nil" do
result = cache.fetch(key, as: nil) { 'block result' }
expect(result).to eq('block result')
end
- it "returns the result of the block when 'as' option is not informed" do
+ it "returns the result of the block when 'as' option is missing" do
result = cache.fetch(key) { 'block result' }
expect(result).to eq('block result')
diff --git a/spec/lib/gitlab/kubernetes/kube_client_spec.rb b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
index 02364e92149..978e64c4407 100644
--- a/spec/lib/gitlab/kubernetes/kube_client_spec.rb
+++ b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
@@ -50,6 +50,36 @@ describe Gitlab::Kubernetes::KubeClient do
end
end
+ describe '#initialize' do
+ shared_examples 'local address' do
+ it 'blocks local addresses' do
+ expect { client }.to raise_error(Gitlab::UrlBlocker::BlockedUrlError)
+ end
+
+ context 'when local requests are allowed' do
+ before do
+ stub_application_setting(allow_local_requests_from_hooks_and_services: true)
+ end
+
+ it 'allows local addresses' do
+ expect { client }.not_to raise_error
+ end
+ end
+ end
+
+ context 'localhost address' do
+ let(:api_url) { 'http://localhost:22' }
+
+ it_behaves_like 'local address'
+ end
+
+ context 'private network address' do
+ let(:api_url) { 'http://192.168.1.2:3003' }
+
+ it_behaves_like 'local address'
+ end
+ end
+
describe '#core_client' do
subject { client.core_client }
diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb
index e90e0aba0a4..312e5e55af8 100644
--- a/spec/lib/gitlab/path_regex_spec.rb
+++ b/spec/lib/gitlab/path_regex_spec.rb
@@ -107,7 +107,7 @@ describe Gitlab::PathRegex do
git = Gitlab.config.git.bin_path
tracked = `cd #{Rails.root} && #{git} ls-files public`
.split("\n")
- .map { |entry| entry.gsub('public/', '') }
+ .map { |entry| entry.start_with?('public/-/') ? '-' : entry.gsub('public/', '') }
.uniq
tracked + %w(assets uploads)
end
diff --git a/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb b/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb
index 420218a695a..936447b8474 100644
--- a/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/matched_metric_query_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::Prometheus::Queries::MatchedMetricQuery do
[{ '__name__' => 'metric_a' },
{ '__name__' => 'metric_b' }]
end
- let(:partialy_empty_series_info) { [{ '__name__' => 'metric_a', 'environment' => '' }] }
+ let(:partially_empty_series_info) { [{ '__name__' => 'metric_a', 'environment' => '' }] }
let(:empty_series_info) { [] }
let(:client) { double('prometheus_client') }
@@ -60,7 +60,7 @@ describe Gitlab::Prometheus::Queries::MatchedMetricQuery do
context 'one of the series info was not found' do
before do
- allow(client).to receive(:series).and_return(partialy_empty_series_info)
+ allow(client).to receive(:series).and_return(partially_empty_series_info)
end
it 'responds with one active and one missing metric' do
expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 1, metrics_missing_requirements: 1 }])
diff --git a/spec/lib/gitlab/quick_actions/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
index 5dae82a63b4..136cfb5bcc5 100644
--- a/spec/lib/gitlab/quick_actions/command_definition_spec.rb
+++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
@@ -72,7 +72,7 @@ describe Gitlab::QuickActions::CommandDefinition do
end
describe "#execute" do
- let(:context) { OpenStruct.new(run: false) }
+ let(:context) { OpenStruct.new(run: false, commands_executed_count: nil) }
context "when the command is a noop" do
it "doesn't execute the command" do
@@ -80,6 +80,7 @@ describe Gitlab::QuickActions::CommandDefinition do
subject.execute(context, nil)
+ expect(context.commands_executed_count).to be_nil
expect(context.run).to be false
end
end
@@ -97,6 +98,7 @@ describe Gitlab::QuickActions::CommandDefinition do
it "doesn't execute the command" do
subject.execute(context, nil)
+ expect(context.commands_executed_count).to be_nil
expect(context.run).to be false
end
end
@@ -112,6 +114,7 @@ describe Gitlab::QuickActions::CommandDefinition do
subject.execute(context, true)
expect(context.run).to be true
+ expect(context.commands_executed_count).to eq(1)
end
end
@@ -120,6 +123,7 @@ describe Gitlab::QuickActions::CommandDefinition do
subject.execute(context, nil)
expect(context.run).to be true
+ expect(context.commands_executed_count).to eq(1)
end
end
end
@@ -134,6 +138,7 @@ describe Gitlab::QuickActions::CommandDefinition do
subject.execute(context, true)
expect(context.run).to be true
+ expect(context.commands_executed_count).to eq(1)
end
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb b/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb
new file mode 100644
index 00000000000..ff8c0825ee4
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_middleware/memory_killer_spec.rb
@@ -0,0 +1,74 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqMiddleware::MemoryKiller do
+ subject { described_class.new }
+ let(:pid) { 999 }
+
+ let(:worker) { double(:worker, class: 'TestWorker') }
+ let(:job) { { 'jid' => 123 } }
+ let(:queue) { 'test_queue' }
+
+ def run
+ thread = subject.call(worker, job, queue) { nil }
+ thread&.join
+ end
+
+ before do
+ allow(subject).to receive(:get_rss).and_return(10.kilobytes)
+ allow(subject).to receive(:pid).and_return(pid)
+ end
+
+ context 'when MAX_RSS is set to 0' do
+ before do
+ stub_const("#{described_class}::MAX_RSS", 0)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:sleep)
+
+ run
+ end
+ end
+
+ context 'when MAX_RSS is exceeded' do
+ before do
+ stub_const("#{described_class}::MAX_RSS", 5.kilobytes)
+ end
+
+ it 'sends the TSTP, TERM and KILL signals at expected times' do
+ expect(subject).to receive(:sleep).with(15 * 60).ordered
+ expect(Process).to receive(:kill).with('SIGTSTP', pid).ordered
+
+ expect(subject).to receive(:sleep).with(30).ordered
+ expect(Process).to receive(:kill).with('SIGTERM', pid).ordered
+
+ expect(subject).to receive(:sleep).with(10).ordered
+ expect(Process).to receive(:kill).with('SIGKILL', pid).ordered
+
+ run
+ end
+
+ it 'sends TSTP and TERM to the pid, but KILL to the pgroup, when running as process leader' do
+ allow(Process).to receive(:getpgrp) { pid }
+ allow(subject).to receive(:sleep)
+
+ expect(Process).to receive(:kill).with('SIGTSTP', pid).ordered
+ expect(Process).to receive(:kill).with('SIGTERM', pid).ordered
+ expect(Process).to receive(:kill).with('SIGKILL', "-#{pid}").ordered
+
+ run
+ end
+ end
+
+ context 'when MAX_RSS is not exceeded' do
+ before do
+ stub_const("#{described_class}::MAX_RSS", 15.kilobytes)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:sleep)
+
+ run
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_middleware/shutdown_spec.rb b/spec/lib/gitlab/sidekiq_middleware/shutdown_spec.rb
deleted file mode 100644
index 0001795c3f0..00000000000
--- a/spec/lib/gitlab/sidekiq_middleware/shutdown_spec.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::SidekiqMiddleware::Shutdown do
- subject { described_class.new }
-
- let(:pid) { Process.pid }
- let(:worker) { double(:worker, class: 'TestWorker') }
- let(:job) { { 'jid' => 123 } }
- let(:queue) { 'test_queue' }
- let(:block) { proc { nil } }
-
- def run
- subject.call(worker, job, queue) { block.call }
- described_class.shutdown_thread&.join
- end
-
- def pop_trace
- subject.trace.pop(true)
- end
-
- before do
- allow(subject).to receive(:get_rss).and_return(10.kilobytes)
- described_class.clear_shutdown_thread
- end
-
- context 'when MAX_RSS is set to 0' do
- before do
- stub_const("#{described_class}::MAX_RSS", 0)
- end
-
- it 'does nothing' do
- expect(subject).not_to receive(:sleep)
-
- run
- end
- end
-
- def expect_shutdown_sequence
- expect(pop_trace).to eq([:sleep, 15 * 60])
- expect(pop_trace).to eq([:kill, 'SIGTSTP', pid])
-
- expect(pop_trace).to eq([:sleep, 30])
- expect(pop_trace).to eq([:kill, 'SIGTERM', pid])
-
- expect(pop_trace).to eq([:sleep, 10])
- expect(pop_trace).to eq([:kill, 'SIGKILL', pid])
- end
-
- context 'when MAX_RSS is exceeded' do
- before do
- stub_const("#{described_class}::MAX_RSS", 5.kilobytes)
- end
-
- it 'sends the TSTP, TERM and KILL signals at expected times' do
- run
-
- expect_shutdown_sequence
- end
- end
-
- context 'when MAX_RSS is not exceeded' do
- before do
- stub_const("#{described_class}::MAX_RSS", 15.kilobytes)
- end
-
- it 'does nothing' do
- expect(subject).not_to receive(:sleep)
-
- run
- end
- end
-
- context 'when WantShutdown is raised' do
- let(:block) { proc { raise described_class::WantShutdown } }
-
- it 'starts the shutdown sequence and re-raises the exception' do
- expect { run }.to raise_exception(described_class::WantShutdown)
-
- # We can't expect 'run' to have joined on the shutdown thread, because
- # it hit an exception.
- shutdown_thread = described_class.shutdown_thread
- expect(shutdown_thread).not_to be_nil
- shutdown_thread.join
-
- expect_shutdown_sequence
- end
- end
-end
diff --git a/spec/lib/gitlab/sidekiq_signals_spec.rb b/spec/lib/gitlab/sidekiq_signals_spec.rb
new file mode 100644
index 00000000000..77ecd1840d2
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_signals_spec.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqSignals do
+ describe '.install' do
+ let(:result) { Hash.new { |h, k| h[k] = 0 } }
+ let(:int_handler) { -> (_) { result['INT'] += 1 } }
+ let(:term_handler) { -> (_) { result['TERM'] += 1 } }
+ let(:other_handler) { -> (_) { result['OTHER'] += 1 } }
+ let(:signals) { { 'INT' => int_handler, 'TERM' => term_handler, 'OTHER' => other_handler } }
+
+ context 'not a process group leader' do
+ before do
+ allow(Process).to receive(:getpgrp) { Process.pid * 2 }
+ end
+
+ it 'does nothing' do
+ expect { described_class.install!(signals) }
+ .not_to change { signals }
+ end
+ end
+
+ context 'as a process group leader' do
+ before do
+ allow(Process).to receive(:getpgrp) { Process.pid }
+ end
+
+ it 'installs its own signal handlers for TERM and INT only' do
+ described_class.install!(signals)
+
+ expect(signals['INT']).not_to eq(int_handler)
+ expect(signals['TERM']).not_to eq(term_handler)
+ expect(signals['OTHER']).to eq(other_handler)
+ end
+
+ %w[INT TERM].each do |signal|
+ it "installs a forwarding signal handler for #{signal}" do
+ described_class.install!(signals)
+
+ expect(described_class)
+ .to receive(:trap)
+ .with(signal, 'IGNORE')
+ .and_return(:original_trap)
+ .ordered
+
+ expect(Process)
+ .to receive(:kill)
+ .with(signal, 0)
+ .ordered
+
+ expect(described_class)
+ .to receive(:trap)
+ .with(signal, :original_trap)
+ .ordered
+
+ signals[signal].call(:cli)
+
+ expect(result[signal]).to eq(1)
+ end
+
+ it "raises if sidekiq no longer traps SIG#{signal}" do
+ signals.delete(signal)
+
+ expect { described_class.install!(signals) }
+ .to raise_error(/Sidekiq should have registered/)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index 5f7a0cca351..8232715d00e 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -95,4 +95,18 @@ describe Gitlab do
expect(described_class.com?).to eq false
end
end
+
+ describe '.ee?' do
+ it 'returns true when using Enterprise Edition' do
+ stub_const('License', Class.new)
+
+ expect(described_class.ee?).to eq(true)
+ end
+
+ it 'returns false when using Community Edition' do
+ hide_const('License')
+
+ expect(described_class.ee?).to eq(false)
+ end
+ end
end
diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb
index 1024e1a25ea..8ccbd90ddb8 100644
--- a/spec/lib/object_storage/direct_upload_spec.rb
+++ b/spec/lib/object_storage/direct_upload_spec.rb
@@ -121,7 +121,7 @@ describe ObjectStorage::DirectUpload do
expect(subject[:MultipartUpload][:PartURLs].length).to eq(2)
end
- it 'part size is mimimum, 5MB' do
+ it 'part size is minimum, 5MB' do
expect(subject[:MultipartUpload][:PartSize]).to eq(5.megabyte)
end
end