diff options
Diffstat (limited to 'spec/lib/gitlab')
89 files changed, 1864 insertions, 786 deletions
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb new file mode 100644 index 00000000000..29f4be76a65 --- /dev/null +++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent do + it { expect(described_class).to respond_to(:name) } + it { expect(described_class).to respond_to(:identifier) } + + it { expect(described_class.new({})).to respond_to(:object_type) } +end diff --git a/spec/lib/gitlab/anonymous_session_spec.rb b/spec/lib/gitlab/anonymous_session_spec.rb new file mode 100644 index 00000000000..94daa0f2470 --- /dev/null +++ b/spec/lib/gitlab/anonymous_session_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do + let(:default_session_id) { '6919a6f1bb119dd7396fadc38fd18d0d' } + let(:additional_session_id) { '7919a6f1bb119dd7396fadc38fd18d0d' } + + subject { new_anonymous_session } + + def new_anonymous_session(session_id = default_session_id) + described_class.new('127.0.0.1', session_id: session_id) + end + + describe '#store_session_id_per_ip' do + it 'adds session id to proper key' do + subject.store_session_id_per_ip + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.smembers("session:lookup:ip:gitlab:127.0.0.1")).to eq [default_session_id] + end + end + + it 'adds expiration time to key' do + Timecop.freeze do + subject.store_session_id_per_ip + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.ttl("session:lookup:ip:gitlab:127.0.0.1")).to eq(24.hours.to_i) + end + end + end + + it 'adds id only once' do + subject.store_session_id_per_ip + subject.store_session_id_per_ip + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.smembers("session:lookup:ip:gitlab:127.0.0.1")).to eq [default_session_id] + end + end + + context 'when there is already one session' do + it 'adds session id to proper key' do + subject.store_session_id_per_ip + new_anonymous_session(additional_session_id).store_session_id_per_ip + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.smembers("session:lookup:ip:gitlab:127.0.0.1")).to contain_exactly(default_session_id, additional_session_id) + end + end + end + end + + describe '#stored_sessions' do + it 'returns all anonymous sessions per ip' do + Gitlab::Redis::SharedState.with do |redis| + redis.sadd("session:lookup:ip:gitlab:127.0.0.1", default_session_id) + redis.sadd("session:lookup:ip:gitlab:127.0.0.1", additional_session_id) + end + + expect(subject.stored_sessions).to eq(2) + end + end + + it 'removes obsolete lookup through ip entries' do + Gitlab::Redis::SharedState.with do |redis| + redis.sadd("session:lookup:ip:gitlab:127.0.0.1", default_session_id) + redis.sadd("session:lookup:ip:gitlab:127.0.0.1", additional_session_id) + end + + subject.cleanup_session_per_ip_entries + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.smembers("session:lookup:ip:gitlab:127.0.0.1")).to eq [additional_session_id] + end + end +end diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb index a9b15c411dc..1e3da4f7c2d 100644 --- a/spec/lib/gitlab/auth/o_auth/user_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb @@ -787,11 +787,25 @@ describe Gitlab::Auth::OAuth::User do end end - describe '#bypass_two_factor?' do - subject { oauth_user.bypass_two_factor? } + describe "#bypass_two_factor?" do + it "when with allow_bypass_two_factor disabled (Default)" do + stub_omniauth_config(allow_bypass_two_factor: false) + expect(oauth_user.bypass_two_factor?).to be_falsey + end + + it "when with allow_bypass_two_factor enabled" do + stub_omniauth_config(allow_bypass_two_factor: true) + expect(oauth_user.bypass_two_factor?).to be_truthy + end + + it "when provider in allow_bypass_two_factor array" do + stub_omniauth_config(allow_bypass_two_factor: [provider]) + expect(oauth_user.bypass_two_factor?).to be_truthy + end - it 'returns always false' do - is_expected.to be_falsey + it "when provider not in allow_bypass_two_factor array" do + stub_omniauth_config(allow_bypass_two_factor: ["foo"]) + expect(oauth_user.bypass_two_factor?).to be_falsey end end end diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 098c33f9cb1..0365d63ea9c 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -587,7 +587,8 @@ describe Gitlab::Auth do :read_project, :build_download_code, :build_read_container_image, - :build_create_container_image + :build_create_container_image, + :build_destroy_container_image ] end diff --git a/spec/lib/gitlab/authorized_keys_spec.rb b/spec/lib/gitlab/authorized_keys_spec.rb index 42bc509eeef..adf36cf1050 100644 --- a/spec/lib/gitlab/authorized_keys_spec.rb +++ b/spec/lib/gitlab/authorized_keys_spec.rb @@ -5,10 +5,81 @@ require 'spec_helper' describe Gitlab::AuthorizedKeys do let(:logger) { double('logger').as_null_object } - subject { described_class.new(logger) } + subject(:authorized_keys) { described_class.new(logger) } + + describe '#accessible?' do + subject { authorized_keys.accessible? } + + context 'authorized_keys file exists' do + before do + create_authorized_keys_fixture + end + + after do + delete_authorized_keys_file + end + + context 'can open file' do + it { is_expected.to be_truthy } + end + + context 'cannot open file' do + before do + allow(File).to receive(:open).and_raise(Errno::EACCES) + end + + it { is_expected.to be_falsey } + end + end + + context 'authorized_keys file does not exist' do + it { is_expected.to be_falsey } + end + end + + describe '#create' do + subject { authorized_keys.create } + + context 'authorized_keys file exists' do + before do + create_authorized_keys_fixture + end + + after do + delete_authorized_keys_file + end + + it { is_expected.to be_truthy } + end + + context 'authorized_keys file does not exist' do + after do + delete_authorized_keys_file + end + + it 'creates authorized_keys file' do + expect(subject).to be_truthy + expect(File.exist?(tmp_authorized_keys_path)).to be_truthy + end + end + + context 'cannot create file' do + before do + allow(File).to receive(:open).and_raise(Errno::EACCES) + end + + it { is_expected.to be_falsey } + end + end describe '#add_key' do + let(:id) { 'key-741' } + + subject { authorized_keys.add_key(id, key) } + context 'authorized_keys file exists' do + let(:key) { 'ssh-rsa AAAAB3NzaDAxx2E trailing garbage' } + before do create_authorized_keys_fixture end @@ -21,19 +92,20 @@ describe Gitlab::AuthorizedKeys do auth_line = "command=\"#{Gitlab.config.gitlab_shell.path}/bin/gitlab-shell key-741\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaDAxx2E" expect(logger).to receive(:info).with('Adding key (key-741): ssh-rsa AAAAB3NzaDAxx2E') - expect(subject.add_key('key-741', 'ssh-rsa AAAAB3NzaDAxx2E trailing garbage')) - .to be_truthy + expect(subject).to be_truthy expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{auth_line}\n") end end context 'authorized_keys file does not exist' do + let(:key) { 'ssh-rsa AAAAB3NzaDAxx2E' } + before do delete_authorized_keys_file end it 'creates the file' do - expect(subject.add_key('key-741', 'ssh-rsa AAAAB3NzaDAxx2E')).to be_truthy + expect(subject).to be_truthy expect(File.exist?(tmp_authorized_keys_path)).to be_truthy end end @@ -47,6 +119,8 @@ describe Gitlab::AuthorizedKeys do ] end + subject { authorized_keys.batch_add_keys(keys) } + context 'authorized_keys file exists' do before do create_authorized_keys_fixture @@ -62,7 +136,7 @@ describe Gitlab::AuthorizedKeys do expect(logger).to receive(:info).with('Adding key (key-12): ssh-dsa ASDFASGADG') expect(logger).to receive(:info).with('Adding key (key-123): ssh-rsa GFDGDFSGSDFG') - expect(subject.batch_add_keys(keys)).to be_truthy + expect(subject).to be_truthy expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{auth_line1}\n#{auth_line2}\n") end @@ -70,7 +144,7 @@ describe Gitlab::AuthorizedKeys do let(:keys) { [double(shell_id: 'key-123', key: "ssh-rsa A\tSDFA\nSGADG")] } it "doesn't add keys" do - expect(subject.batch_add_keys(keys)).to be_falsey + expect(subject).to be_falsey expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n") end end @@ -82,16 +156,28 @@ describe Gitlab::AuthorizedKeys do end it 'creates the file' do - expect(subject.batch_add_keys(keys)).to be_truthy + expect(subject).to be_truthy expect(File.exist?(tmp_authorized_keys_path)).to be_truthy end end end describe '#rm_key' do + let(:key) { 'key-741' } + + subject { authorized_keys.rm_key(key) } + context 'authorized_keys file exists' do + let(:other_line) { "command=\"#{Gitlab.config.gitlab_shell.path}/bin/gitlab-shell key-742\",options ssh-rsa AAAAB3NzaDAxx2E" } + let(:delete_line) { "command=\"#{Gitlab.config.gitlab_shell.path}/bin/gitlab-shell key-741\",options ssh-rsa AAAAB3NzaDAxx2E" } + before do create_authorized_keys_fixture + + File.open(tmp_authorized_keys_path, 'a') do |auth_file| + auth_file.puts delete_line + auth_file.puts other_line + end end after do @@ -99,16 +185,10 @@ describe Gitlab::AuthorizedKeys do end it "removes the right line" do - other_line = "command=\"#{Gitlab.config.gitlab_shell.path}/bin/gitlab-shell key-742\",options ssh-rsa AAAAB3NzaDAxx2E" - delete_line = "command=\"#{Gitlab.config.gitlab_shell.path}/bin/gitlab-shell key-741\",options ssh-rsa AAAAB3NzaDAxx2E" erased_line = delete_line.gsub(/./, '#') - File.open(tmp_authorized_keys_path, 'a') do |auth_file| - auth_file.puts delete_line - auth_file.puts other_line - end expect(logger).to receive(:info).with('Removing key (key-741)') - expect(subject.rm_key('key-741')).to be_truthy + expect(subject).to be_truthy expect(File.read(tmp_authorized_keys_path)).to eq("existing content\n#{erased_line}\n#{other_line}\n") end end @@ -118,13 +198,13 @@ describe Gitlab::AuthorizedKeys do delete_authorized_keys_file end - it 'returns false' do - expect(subject.rm_key('key-741')).to be_falsey - end + it { is_expected.to be_falsey } end end describe '#clear' do + subject { authorized_keys.clear } + context 'authorized_keys file exists' do before do create_authorized_keys_fixture @@ -134,9 +214,7 @@ describe Gitlab::AuthorizedKeys do delete_authorized_keys_file end - it "returns true" do - expect(subject.clear).to be_truthy - end + it { is_expected.to be_truthy } end context 'authorized_keys file does not exist' do @@ -144,13 +222,13 @@ describe Gitlab::AuthorizedKeys do delete_authorized_keys_file end - it "still returns true" do - expect(subject.clear).to be_truthy - end + it { is_expected.to be_truthy } end end describe '#list_key_ids' do + subject { authorized_keys.list_key_ids } + context 'authorized_keys file exists' do before do create_authorized_keys_fixture( @@ -163,9 +241,7 @@ describe Gitlab::AuthorizedKeys do delete_authorized_keys_file end - it 'returns array of key IDs' do - expect(subject.list_key_ids).to eq([1, 2, 3, 9000]) - end + it { is_expected.to eq([1, 2, 3, 9000]) } end context 'authorized_keys file does not exist' do @@ -173,9 +249,7 @@ describe Gitlab::AuthorizedKeys do delete_authorized_keys_file end - it 'returns an empty array' do - expect(subject.list_key_ids).to be_empty - end + it { is_expected.to be_empty } end end diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb index ad4fa4fe03a..c1f6871a568 100644 --- a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, :migration, schema: 20190315191339 do let(:namespaces) { table(:namespaces) } diff --git a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb index 740781f1aa5..fd35ddc49a2 100644 --- a/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb +++ b/spec/lib/gitlab/background_migration/reset_merge_status_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::BackgroundMigration::ResetMergeStatus, :migration, schema: 20190528180441 do let(:namespaces) { table(:namespaces) } diff --git a/spec/lib/gitlab/checks/diff_check_spec.rb b/spec/lib/gitlab/checks/diff_check_spec.rb index a341dfa5636..b9134b8d6ab 100644 --- a/spec/lib/gitlab/checks/diff_check_spec.rb +++ b/spec/lib/gitlab/checks/diff_check_spec.rb @@ -20,9 +20,8 @@ describe Gitlab::Checks::DiffCheck do allow(project).to receive(:lfs_enabled?).and_return(false) end - it 'skips the validation' do - expect(subject).not_to receive(:validate_diff) - expect(subject).not_to receive(:validate_file_paths) + it 'does not invoke :lfs_file_locks_validation' do + expect(subject).not_to receive(:lfs_file_locks_validation) subject.validate! end diff --git a/spec/lib/gitlab/checks/project_created_spec.rb b/spec/lib/gitlab/checks/project_created_spec.rb index 14cb5e6ec66..373fef2a240 100644 --- a/spec/lib/gitlab/checks/project_created_spec.rb +++ b/spec/lib/gitlab/checks/project_created_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::Checks::ProjectCreated, :clean_gitlab_redis_shared_state do let(:user) { create(:user) } diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb index 3ca977aa48d..3de397760b4 100644 --- a/spec/lib/gitlab/checks/project_moved_spec.rb +++ b/spec/lib/gitlab/checks/project_moved_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do let(:user) { create(:user) } diff --git a/spec/lib/gitlab/ci/build/policy/refs_spec.rb b/spec/lib/gitlab/ci/build/policy/refs_spec.rb index 43c5d3ec980..8fc1e0a4e88 100644 --- a/spec/lib/gitlab/ci/build/policy/refs_spec.rb +++ b/spec/lib/gitlab/ci/build/policy/refs_spec.rb @@ -84,6 +84,20 @@ describe Gitlab::Ci::Build::Policy::Refs do .not_to be_satisfied_by(pipeline) end end + + context 'when source is external_pull_request_event' do + let(:pipeline) { build_stubbed(:ci_pipeline, source: :external_pull_request_event) } + + it 'is satisfied with only: external_pull_request' do + expect(described_class.new(%w[external_pull_requests])) + .to be_satisfied_by(pipeline) + end + + it 'is not satisfied with only: external_pull_request_event' do + expect(described_class.new(%w[external_pull_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/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb index 775550f2acc..c7a5ac783b3 100644 --- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb +++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb @@ -87,7 +87,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do .with(cluster, environment: deployment.environment) .and_return(namespace_builder) - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService) + expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService) .to receive(:new) .with(cluster: cluster, kubernetes_namespace: kubernetes_namespace) .and_return(service) @@ -107,7 +107,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do it 'creates a namespace using the tokenless record' do expect(Clusters::BuildKubernetesNamespaceService).not_to receive(:new) - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService) + expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService) .to receive(:new) .with(cluster: cluster, kubernetes_namespace: kubernetes_namespace) .and_return(service) @@ -123,7 +123,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do end it 'does not create a namespace' do - expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:new) + expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:new) subject 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 dd536a241bd..af995f4869a 100644 --- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb @@ -41,6 +41,12 @@ describe Gitlab::Ci::Config::External::File::Base do end describe '#valid?' do + context 'when location is not a string' do + let(:location) { %w(some/file.txt other/file.txt) } + + it { is_expected.not_to be_valid } + end + context 'when location is not a YAML file' do let(:location) { 'some/file.txt' } diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb index bf9ff922c05..ba4f841cf43 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb @@ -128,4 +128,38 @@ describe Gitlab::Ci::Pipeline::Chain::Build do expect(pipeline.target_sha).to eq(merge_request.target_branch_sha) end end + + context 'when pipeline is running for an external pull request' do + let(:command) do + Gitlab::Ci::Pipeline::Chain::Command.new( + source: :external_pull_request_event, + origin_ref: 'feature', + checkout_sha: project.commit.id, + after_sha: nil, + before_sha: nil, + source_sha: external_pull_request.source_sha, + target_sha: external_pull_request.target_sha, + trigger_request: nil, + schedule: nil, + external_pull_request: external_pull_request, + project: project, + current_user: user) + end + + let(:external_pull_request) { build(:external_pull_request, project: project) } + + before do + step.perform! + end + + it 'correctly indicated that this is an external pull request pipeline' do + expect(pipeline).to be_external_pull_request_event + expect(pipeline.external_pull_request).to eq(external_pull_request) + end + + it 'correctly sets source sha and target sha to pipeline' do + expect(pipeline.source_sha).to eq(external_pull_request.source_sha) + expect(pipeline.target_sha).to eq(external_pull_request.target_sha) + end + end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 91c559dcd9b..cf496b79a62 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -50,6 +50,32 @@ module Gitlab end end + describe 'interruptible entry' do + describe 'interruptible job' do + let(:config) do + YAML.dump(rspec: { script: 'rspec', interruptible: true }) + end + + it { expect(subject[:interruptible]).to be_truthy } + end + + describe 'interruptible job with default value' do + let(:config) do + YAML.dump(rspec: { script: 'rspec' }) + end + + it { expect(subject).not_to have_key(:interruptible) } + end + + describe 'uninterruptible job' do + let(:config) do + YAML.dump(rspec: { script: 'rspec', interruptible: false }) + end + + it { expect(subject[:interruptible]).to be_falsy } + end + end + describe 'retry entry' do context 'when retry count is specified' do let(:config) do diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb index 2990594c538..1b4d366ce7b 100644 --- a/spec/lib/gitlab/danger/helper_spec.rb +++ b/spec/lib/gitlab/danger/helper_spec.rb @@ -11,16 +11,62 @@ describe Gitlab::Danger::Helper do class FakeDanger include Gitlab::Danger::Helper - attr_reader :git + attr_reader :git, :gitlab - def initialize(git:) + def initialize(git:, gitlab:) @git = git + @gitlab = gitlab end end let(:fake_git) { double('fake-git') } - subject(:helper) { FakeDanger.new(git: fake_git) } + let(:mr_author) { nil } + let(:fake_gitlab) { double('fake-gitlab', mr_author: mr_author) } + + subject(:helper) { FakeDanger.new(git: fake_git, gitlab: fake_gitlab) } + + describe '#gitlab_helper' do + context 'when gitlab helper is not available' do + let(:fake_gitlab) { nil } + + it 'returns nil' do + expect(helper.gitlab_helper).to be_nil + end + end + + context 'when gitlab helper is available' do + it 'returns the gitlab helper' do + expect(helper.gitlab_helper).to eq(fake_gitlab) + end + end + end + + describe '#release_automation?' do + context 'when gitlab helper is not available' do + it 'returns false' do + expect(helper.release_automation?).to be_falsey + end + end + + context 'when gitlab helper is available' do + context "but the MR author isn't the RELEASE_TOOLS_BOT" do + let(:mr_author) { 'johnmarston' } + + it 'returns false' do + expect(helper.release_automation?).to be_falsey + end + end + + context 'and the MR author is the RELEASE_TOOLS_BOT' do + let(:mr_author) { described_class::RELEASE_TOOLS_BOT } + + it 'returns true' do + expect(helper.release_automation?).to be_truthy + end + end + end + end describe '#all_changed_files' do subject { helper.all_changed_files } @@ -168,9 +214,13 @@ describe Gitlab::Danger::Helper do 'Gemfile.lock' | :backend 'Procfile' | :backend 'Rakefile' | :backend - '.gitlab-ci.yml' | :backend 'FOO_VERSION' | :backend + '.gitlab-ci.yml' | :engineering_productivity + '.gitlab/ci/cng.gitlab-ci.yml' | :engineering_productivity + '.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | :engineering_productivity + 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | :backend + 'ee/FOO_VERSION' | :unknown 'db/schema.rb' | :database diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb index 171f2344e82..ca036390bde 100644 --- a/spec/lib/gitlab/danger/teammate_spec.rb +++ b/spec/lib/gitlab/danger/teammate_spec.rb @@ -28,7 +28,7 @@ describe Gitlab::Danger::Teammate do end context 'when labels contain Create and the category is test' do - let(:labels) { ['Create'] } + let(:labels) { ['devops::create'] } context 'when role is Test Automation Engineer, Create' do let(:role) { 'Test Automation Engineer, Create' } @@ -50,6 +50,14 @@ describe Gitlab::Danger::Teammate do end end + context 'when role is Test Automation Engineer' do + let(:role) { 'Test Automation Engineer' } + + it '#reviewer? returns false' do + expect(subject.reviewer?(project, :test, labels)).to be_falsey + end + end + context 'when role is Test Automation Engineer, Manage' do let(:role) { 'Test Automation Engineer, Manage' } @@ -57,6 +65,18 @@ describe Gitlab::Danger::Teammate do expect(subject.reviewer?(project, :test, labels)).to be_falsey end end + + context 'when role is Backend Engineer, Engineering Productivity' do + let(:role) { 'Backend Engineer, Engineering Productivity' } + + it '#reviewer? returns true' do + expect(subject.reviewer?(project, :engineering_productivity, labels)).to be_truthy + end + + it '#maintainer? returns false' do + expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_falsey + end + end end end diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 2731fc8573f..49f92f14559 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -576,6 +576,38 @@ describe Gitlab::Database::MigrationHelpers do model.rename_column_concurrently(:users, :old, :new) end + + context 'when default is false' do + let(:old_column) do + double(:column, + type: :boolean, + limit: nil, + default: false, + null: false, + precision: nil, + scale: nil) + end + + it 'copies the default to the new column' do + expect(model).to receive(:change_column_default) + .with(:users, :new, old_column.default) + + model.rename_column_concurrently(:users, :old, :new) + end + end + end + end + + describe '#undo_rename_column_concurrently' do + it 'reverses the operations of rename_column_concurrently' do + expect(model).to receive(:check_trigger_permissions!).with(:users) + + expect(model).to receive(:remove_rename_triggers_for_postgresql) + .with(:users, /trigger_.{12}/) + + expect(model).to receive(:remove_column).with(:users, :new) + + model.undo_rename_column_concurrently(:users, :old, :new) end end @@ -592,6 +624,80 @@ describe Gitlab::Database::MigrationHelpers do end end + describe '#undo_cleanup_concurrent_column_rename' do + context 'in a transaction' do + it 'raises RuntimeError' do + allow(model).to receive(:transaction_open?).and_return(true) + + expect { model.undo_cleanup_concurrent_column_rename(:users, :old, :new) } + .to raise_error(RuntimeError) + end + end + + context 'outside a transaction' do + let(:new_column) do + double(:column, + type: :integer, + limit: 8, + default: 0, + null: false, + precision: 5, + scale: 1) + end + + let(:trigger_name) { model.rename_trigger_name(:users, :old, :new) } + + before do + allow(model).to receive(:transaction_open?).and_return(false) + allow(model).to receive(:column_for).and_return(new_column) + end + + it 'reverses the operations of cleanup_concurrent_column_rename' do + expect(model).to receive(:check_trigger_permissions!).with(:users) + + expect(model).to receive(:install_rename_triggers_for_postgresql) + .with(trigger_name, '"users"', '"old"', '"new"') + + expect(model).to receive(:add_column) + .with(:users, :old, :integer, + limit: new_column.limit, + precision: new_column.precision, + scale: new_column.scale) + + expect(model).to receive(:change_column_default) + .with(:users, :old, new_column.default) + + expect(model).to receive(:update_column_in_batches) + + expect(model).to receive(:change_column_null).with(:users, :old, false) + + expect(model).to receive(:copy_indexes).with(:users, :new, :old) + expect(model).to receive(:copy_foreign_keys).with(:users, :new, :old) + + model.undo_cleanup_concurrent_column_rename(:users, :old, :new) + end + + context 'when default is false' do + let(:new_column) do + double(:column, + type: :boolean, + limit: nil, + default: false, + null: false, + precision: nil, + scale: nil) + end + + it 'copies the default to the old column' do + expect(model).to receive(:change_column_default) + .with(:users, :old, new_column.default) + + model.undo_cleanup_concurrent_column_rename(:users, :old, :new) + end + end + end + end + describe '#change_column_type_concurrently' do it 'changes the column type' do expect(model).to receive(:rename_column_concurrently) @@ -619,10 +725,18 @@ describe Gitlab::Database::MigrationHelpers do .with(/CREATE OR REPLACE FUNCTION foo()/m) expect(model).to receive(:execute) + .with(/DROP TRIGGER IF EXISTS foo/m) + + expect(model).to receive(:execute) .with(/CREATE TRIGGER foo/m) model.install_rename_triggers_for_postgresql('foo', :users, :old, :new) end + + it 'does not fail if trigger already exists' do + model.install_rename_triggers_for_postgresql('foo', :users, :old, :new) + model.install_rename_triggers_for_postgresql('foo', :users, :old, :new) + end end describe '#remove_rename_triggers_for_postgresql' do @@ -1169,33 +1283,19 @@ describe Gitlab::Database::MigrationHelpers do describe '#perform_background_migration_inline?' do it 'returns true in a test environment' do - allow(Rails.env) - .to receive(:test?) - .and_return(true) + stub_rails_env('test') expect(model.perform_background_migration_inline?).to eq(true) end it 'returns true in a development environment' do - allow(Rails.env) - .to receive(:test?) - .and_return(false) - - allow(Rails.env) - .to receive(:development?) - .and_return(true) + stub_rails_env('development') expect(model.perform_background_migration_inline?).to eq(true) end it 'returns false in a production environment' do - allow(Rails.env) - .to receive(:test?) - .and_return(false) - - allow(Rails.env) - .to receive(:development?) - .and_return(false) + stub_rails_env('production') expect(model.perform_background_migration_inline?).to eq(false) end diff --git a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb index eed2a1b7b48..e6321d48e11 100644 --- a/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb +++ b/spec/lib/gitlab/database_importers/common_metrics/importer_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DatabaseImporters::CommonMetrics::Importer do subject { described_class.new } diff --git a/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb b/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb index 94f544e59b3..e4e8a85e7bc 100644 --- a/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb +++ b/spec/lib/gitlab/database_importers/common_metrics/prometheus_metric_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DatabaseImporters::CommonMetrics::PrometheusMetric do it 'group enum equals ::PrometheusMetric' do diff --git a/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb new file mode 100644 index 00000000000..aab6fbcbbd1 --- /dev/null +++ b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb @@ -0,0 +1,292 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService do + describe '#execute' do + let(:result) { subject.execute! } + + let(:prometheus_settings) do + { + enable: true, + listen_address: 'localhost:9090' + } + end + + before do + stub_config(prometheus: prometheus_settings) + end + + context 'without application_settings' do + it 'does not fail' do + expect(subject).to receive(:log_error).and_call_original + expect(result).to eq( + status: :success + ) + + expect(Project.count).to eq(0) + expect(Group.count).to eq(0) + end + end + + context 'without admin users' do + let(:application_setting) { Gitlab::CurrentSettings.current_application_settings } + + before do + allow(ApplicationSetting).to receive(:current_without_cache) { application_setting } + end + + it 'does not fail' do + expect(subject).to receive(:log_error).and_call_original + expect(result).to eq( + status: :success + ) + + expect(Project.count).to eq(0) + expect(Group.count).to eq(0) + end + end + + context 'with admin users' do + let(:project) { result[:project] } + let(:group) { result[:group] } + let(:application_setting) { Gitlab::CurrentSettings.current_application_settings } + + let!(:user) { create(:user, :admin) } + + before do + allow(ApplicationSetting).to receive(:current_without_cache) { application_setting } + application_setting.allow_local_requests_from_web_hooks_and_services = true + end + + shared_examples 'has prometheus service' do |listen_address| + it do + expect(result[:status]).to eq(:success) + + prometheus = project.prometheus_service + expect(prometheus).not_to eq(nil) + expect(prometheus.api_url).to eq(listen_address) + expect(prometheus.active).to eq(true) + expect(prometheus.manual_configuration).to eq(true) + end + end + + it_behaves_like 'has prometheus service', 'http://localhost:9090' + + it 'creates group' do + expect(result[:status]).to eq(:success) + expect(group).to be_persisted + expect(group.name).to eq('GitLab Instance Administrators') + expect(group.path).to start_with('gitlab-instance-administrators') + expect(group.path.split('-').last.length).to eq(8) + expect(group.visibility_level).to eq(described_class::VISIBILITY_LEVEL) + end + + it 'creates project with internal visibility' do + expect(result[:status]).to eq(:success) + expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + expect(project).to be_persisted + end + + it 'creates project with internal visibility even when internal visibility is restricted' do + application_setting.restricted_visibility_levels = [Gitlab::VisibilityLevel::INTERNAL] + + expect(result[:status]).to eq(:success) + expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + expect(project).to be_persisted + end + + it 'creates project with correct name and description' do + path = 'administration/monitoring/gitlab_instance_administration_project/index' + docs_path = Rails.application.routes.url_helpers.help_page_path(path) + + expect(result[:status]).to eq(:success) + expect(project.name).to eq(described_class::PROJECT_NAME) + expect(project.description).to eq( + 'This project is automatically generated and will be used to help monitor this GitLab instance. ' \ + "[More information](#{docs_path})" + ) + expect(File).to exist("doc/#{path}.md") + end + + it 'adds all admins as maintainers' do + admin1 = create(:user, :admin) + admin2 = create(:user, :admin) + create(:user) + + expect(result[:status]).to eq(:success) + expect(project.owner).to eq(group) + expect(group.members.collect(&:user)).to contain_exactly(user, admin1, admin2) + expect(group.members.collect(&:access_level)).to contain_exactly( + Gitlab::Access::OWNER, + Gitlab::Access::MAINTAINER, + Gitlab::Access::MAINTAINER + ) + end + + it 'saves the project id' do + expect(result[:status]).to eq(:success) + expect(application_setting.instance_administration_project_id).to eq(project.id) + end + + it 'returns error when saving project ID fails' do + allow(application_setting).to receive(:save) { false } + + expect { result }.to raise_error(StandardError, 'Could not save project ID') + end + + context 'when project already exists' do + let(:existing_group) { create(:group) } + let(:existing_project) { create(:project, namespace: existing_group) } + + before do + admin1 = create(:user, :admin) + admin2 = create(:user, :admin) + + existing_group.add_owner(user) + existing_group.add_users([admin1, admin2], Gitlab::Access::MAINTAINER) + + application_setting.instance_administration_project_id = existing_project.id + end + + it 'does not fail' do + expect(subject).to receive(:log_error).and_call_original + expect(result[:status]).to eq(:success) + + expect(Project.count).to eq(1) + expect(Group.count).to eq(1) + end + end + + context 'when local requests from hooks and services are not allowed' do + before do + application_setting.allow_local_requests_from_web_hooks_and_services = false + end + + it_behaves_like 'has prometheus service', 'http://localhost:9090' + + it 'does not overwrite the existing whitelist' do + application_setting.outbound_local_requests_whitelist = ['example.com'] + + expect(result[:status]).to eq(:success) + expect(application_setting.outbound_local_requests_whitelist).to contain_exactly( + 'example.com', 'localhost' + ) + end + end + + context 'with non default prometheus address' do + let(:listen_address) { 'https://localhost:9090' } + + let(:prometheus_settings) do + { + enable: true, + listen_address: listen_address + } + end + + it_behaves_like 'has prometheus service', 'https://localhost:9090' + + context 'with :9090 symbol' do + let(:listen_address) { :':9090' } + + it_behaves_like 'has prometheus service', 'http://localhost:9090' + end + + context 'with 0.0.0.0:9090' do + let(:listen_address) { '0.0.0.0:9090' } + + it_behaves_like 'has prometheus service', 'http://localhost:9090' + end + end + + context 'when prometheus setting is not present in gitlab.yml' do + before do + allow(Gitlab.config).to receive(:prometheus).and_raise(Settingslogic::MissingSetting) + end + + it 'does not fail' do + expect(result).to include(status: :success) + expect(project.prometheus_service).to be_nil + end + end + + context 'when prometheus setting is nil' do + before do + stub_config(prometheus: nil) + end + + it 'does not fail' do + expect(result).to include(status: :success) + expect(project.prometheus_service).to be_nil + end + end + + context 'when prometheus setting is disabled in gitlab.yml' do + let(:prometheus_settings) do + { + enable: false, + listen_address: 'http://localhost:9090' + } + end + + it 'does not configure prometheus' do + expect(result).to include(status: :success) + expect(project.prometheus_service).to be_nil + end + end + + context 'when prometheus listen address is blank in gitlab.yml' do + let(:prometheus_settings) { { enable: true, listen_address: '' } } + + it 'does not configure prometheus' do + expect(result).to include(status: :success) + expect(project.prometheus_service).to be_nil + end + end + + context 'when project cannot be created' do + let(:project) { build(:project) } + + before do + project.errors.add(:base, "Test error") + + expect_next_instance_of(::Projects::CreateService) do |project_create_service| + expect(project_create_service).to receive(:execute) + .and_return(project) + end + end + + it 'returns error' do + expect(subject).to receive(:log_error).and_call_original + expect { result }.to raise_error(StandardError, 'Could not create project') + end + end + + context 'when user cannot be added to project' do + before do + subject.instance_variable_set(:@instance_admins, [user, build(:user, :admin)]) + end + + it 'returns error' do + expect(subject).to receive(:log_error).and_call_original + expect { result }.to raise_error(StandardError, 'Could not add admins as members') + end + end + + context 'when prometheus manual configuration cannot be saved' do + let(:prometheus_settings) do + { + enable: true, + listen_address: 'httpinvalid://localhost:9090' + } + end + + it 'returns error' do + expect(subject).to receive(:log_error).and_call_original + expect { result }.to raise_error(StandardError, 'Could not save prometheus manual configuration') + end + end + end + end +end diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 77e58b6d5c7..8d37de32179 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -347,6 +347,17 @@ describe Gitlab::Database do pool.disconnect! end end + + it 'allows setting of a custom hostname and port' do + pool = described_class.create_connection_pool(5, '127.0.0.1', 5432) + + begin + expect(pool.spec.config[:host]).to eq('127.0.0.1') + expect(pool.spec.config[:port]).to eq(5432) + ensure + pool.disconnect! + end + end end describe '.cached_column_exists?' do diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb index 3eb5db51224..6d61edaa870 100644 --- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::CartfileLinker do describe '.support?' do 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 6bef6f57e64..cc1f09628ef 100644 --- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::ComposerJsonLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb index 6ecdb0d1247..c6b6dfa77cb 100644 --- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::GemfileLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb index 256fe58925c..c1cbfa31684 100644 --- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::GemspecLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb index f620d1b590c..9f8542a76c9 100644 --- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::GodepsJsonLinker do describe '.support?' 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 71e9381eaad..eb0c5e0675a 100644 --- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::PackageJsonLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb index 9bfb1b13a2b..5b69ef5af24 100644 --- a/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb +++ b/spec/lib/gitlab/dependency_linker/parser/gemfile_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::Parser::Gemfile do describe '#parse' do diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb index eb81bc07760..77326e73505 100644 --- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::PodfileLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb index 938726dd434..d522a08cdd9 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::PodspecJsonLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb index 540eb2fadfe..baabd0c0460 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::PodspecLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb index 957a87985a2..04ac5f10479 100644 --- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker::RequirementsTxtLinker do describe '.support?' do diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb index 98e46d62ca0..3ea3334caf0 100644 --- a/spec/lib/gitlab/dependency_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::DependencyLinker do describe '.link' do diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index dce56bbd2c4..d221f39c2ed 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -1,14 +1,14 @@ -require 'rails_helper' +require 'spec_helper' RSpec.describe Gitlab::Favicon, :request_store do describe '.main' do it 'defaults to favicon.png' do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + stub_rails_env('production') expect(described_class.main).to match_asset_path '/assets/favicon.png' end it 'has blue favicon for development', unless: Gitlab.ee? do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) + stub_rails_env('development') expect(described_class.main).to match_asset_path '/assets/favicon-blue.png' end @@ -24,7 +24,7 @@ RSpec.describe Gitlab::Favicon, :request_store do context 'asset host' do before do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + stub_rails_env('production') end it 'returns a relative url when the asset host is not configured' do diff --git a/spec/lib/gitlab/file_markdown_link_builder_spec.rb b/spec/lib/gitlab/file_markdown_link_builder_spec.rb index feb2776c5d0..d9e2e162ae8 100644 --- a/spec/lib/gitlab/file_markdown_link_builder_spec.rb +++ b/spec/lib/gitlab/file_markdown_link_builder_spec.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::FileMarkdownLinkBuilder do let(:custom_class) do diff --git a/spec/lib/gitlab/file_type_detection_spec.rb b/spec/lib/gitlab/file_type_detection_spec.rb index 5e9b8988cc8..22ec7d414e8 100644 --- a/spec/lib/gitlab/file_type_detection_spec.rb +++ b/spec/lib/gitlab/file_type_detection_spec.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::FileTypeDetection do def upload_fixture(filename) diff --git a/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb b/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb new file mode 100644 index 00000000000..503fe897e29 --- /dev/null +++ b/spec/lib/gitlab/fogbugz_import/project_creator_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::FogbugzImport::ProjectCreator do + let(:user) { create(:user) } + + let(:repo) do + instance_double(Gitlab::FogbugzImport::Repository, + name: 'Vim', + safe_name: 'vim', + path: 'vim', + raw_data: '') + end + + let(:uri) { 'https://testing.fogbugz.com' } + let(:token) { 'token' } + let(:fb_session) { { uri: uri, token: token } } + let(:project_creator) { described_class.new(repo, fb_session, user.namespace, user) } + + subject do + project_creator.execute + end + + it 'creates project with private visibility level' do + expect(subject.persisted?).to eq(true) + expect(subject.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) + end +end diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 4d2f08f95fc..790b0428d19 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -102,6 +102,23 @@ describe Gitlab::Gfm::ReferenceRewriter do end end + context 'with a commit' do + let(:old_project) { create(:project, :repository, name: 'old-project', group: group) } + let(:commit) { old_project.commit } + + context 'reference to an absolute URL to a commit' do + let(:text) { Gitlab::UrlBuilder.build(commit) } + + it { is_expected.to eq(text) } + end + + context 'reference to a commit' do + let(:text) { commit.id } + + it { is_expected.to eq("#{old_project_ref}@#{text}") } + end + end + context 'reference contains project milestone' do let!(:milestone) do create(:milestone, title: '9.0', project: old_project) diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb index 81658874be7..be6ab0c1200 100644 --- a/spec/lib/gitlab/git/diff_collection_spec.rb +++ b/spec/lib/gitlab/git/diff_collection_spec.rb @@ -74,6 +74,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do end end + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + context 'when limiting is disabled' do let(:limits) { false } @@ -100,6 +105,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do expect(subject.size).to eq(3) end end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end end end @@ -120,6 +130,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('0+') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq 1000 } + end + it { expect(subject.size).to eq(0) } context 'when limiting is disabled' do @@ -139,6 +155,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('3') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(3) } end end @@ -164,6 +186,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('10+') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq 10 } + end + it { expect(subject.size).to eq(10) } context 'when limiting is disabled' do @@ -183,6 +211,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('11') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(11) } end end @@ -204,6 +238,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('3+') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq 120 } + end + it { expect(subject.size).to eq(3) } context 'when limiting is disabled' do @@ -223,6 +263,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('11') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(11) } end end @@ -248,6 +294,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('10') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(10) } end end @@ -270,6 +322,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('9+') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(9) } context 'when limiting is disabled' do @@ -289,6 +347,12 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('10') } end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq file_count * line_count } + end + it { expect(subject.size).to eq(10) } end end @@ -316,6 +380,11 @@ describe Gitlab::Git::DiffCollection, :seed_helper do subject { super().real_size } it { is_expected.to eq('0')} end + + describe '#line_count' do + subject { super().line_count } + it { is_expected.to eq 0 } + end end describe '#each' do diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb index 1a4168f7317..474240cf620 100644 --- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb +++ b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb @@ -35,7 +35,7 @@ describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do let(:args) { ['refs/heads/master', 1] } before do - allow(Gitlab::RuggedInstrumentation).to receive(:peek_enabled?).and_return(true) + allow(Gitlab::PerformanceBar).to receive(:enabled_for_request?).and_return(true) end it 'instruments Rugged call' do diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index e9fb6c0125c..1c5f72a4396 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -27,6 +27,16 @@ describe Gitlab::GitalyClient do end end + describe '.filesystem_id' do + it 'returns an empty string when the storage is not found in the response' do + response = double("response") + allow(response).to receive(:storage_statuses).and_return([]) + allow_any_instance_of(Gitlab::GitalyClient::ServerService).to receive(:info).and_return(response) + + expect(described_class.filesystem_id('default')).to eq(nil) + end + end + describe '.stub_class' do it 'returns the gRPC health check stub' do expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub) @@ -255,7 +265,7 @@ describe Gitlab::GitalyClient do context 'in production and when RequestStore is enabled', :request_store do before do - allow(Rails.env).to receive(:production?).and_return(true) + stub_rails_env('production') end context 'when the maximum number of calls is enforced by a feature flag' do diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 47e6f5d4220..a3d7e42733d 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' describe Gitlab::Gpg::Commit do describe '#signature' do diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index 1a2c6ef25c4..1dfca0b056c 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do describe '#run' do diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 48bbd7f854c..77d318c9b23 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' describe Gitlab::Gpg do describe '.fingerprints_from_key' do diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb index d60d1b7559a..aada9285b31 100644 --- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb +++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb @@ -30,7 +30,11 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do describe '#authorized_resolve' do let(:presented_object) { double('presented object') } let(:presented_type) { double('parent type', object: presented_object) } - subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) } + let(:query_type) { GraphQL::ObjectType.new } + let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)} + let(:query_context) { OpenStruct.new(schema: schema) } + let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema, context: query_context), values: { current_user: current_user }, object: nil) } + subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) } context 'scalar types' do shared_examples 'checking permissions on the presented object' do diff --git a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb index 50138d272c4..23762666ba8 100644 --- a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb +++ b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb @@ -46,9 +46,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do end end - describe '#authorized?' do + describe '#authorized_resource?' do it 'is true' do - expect(loading_resource.authorized?(project)).to be(true) + expect(loading_resource.authorized_resource?(project)).to be(true) end end end @@ -72,9 +72,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do end end - describe '#authorized?' do + describe '#authorized_resource?' do it 'is false' do - expect(loading_resource.authorized?(project)).to be(false) + expect(loading_resource.authorized_resource?(project)).to be(false) end end end @@ -121,9 +121,9 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do end end - describe '#authorized?' do + describe '#authorized_resource?' do it 'raises a comprehensive error message' do - expect { loading_resource.authorized?(project) }.to raise_error(error) + expect { loading_resource.authorized_resource?(project) }.to raise_error(error) end end end diff --git a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb index fefa2881b18..4eb121794e1 100644 --- a/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb +++ b/spec/lib/gitlab/graphql/connections/keyset_connection_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Graphql::Connections::KeysetConnection do end def encoded_property(value) - Base64.strict_encode64(value.to_s) + Base64Bp.urlsafe_encode64(value.to_s, padding: false) end describe '#cursor_from_nodes' do diff --git a/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb index 46dd1777285..22d8aa4274a 100644 --- a/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb +++ b/spec/lib/gitlab/graphql/loaders/batch_lfs_oid_loader_spec.rb @@ -12,7 +12,7 @@ describe Gitlab::Graphql::Loaders::BatchLfsOidLoader do it 'batch-resolves LFS blob IDs' do expect(Gitlab::Git::Blob).to receive(:batch_lfs_pointers).once.and_call_original - result = batch do + result = batch_sync do [blob, otherblob].map { |b| described_class.new(repository, b.id).find } end diff --git a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb index 4609593ef6a..a4bbd868558 100644 --- a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb +++ b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb @@ -9,8 +9,8 @@ describe Gitlab::Graphql::Loaders::BatchModelLoader do issue_result = described_class.new(Issue, issue.id).find user_result = described_class.new(User, user.id).find - expect(issue_result.__sync).to eq(issue) - expect(user_result.__sync).to eq(user) + expect(issue_result.sync).to eq(issue) + expect(user_result.sync).to eq(user) end it 'only queries once per model' do @@ -21,7 +21,7 @@ describe Gitlab::Graphql::Loaders::BatchModelLoader do expect do [described_class.new(User, other_user.id).find, described_class.new(User, user.id).find, - described_class.new(Issue, issue.id).find].map(&:__sync) + described_class.new(Issue, issue.id).find].map(&:sync) end.not_to exceed_query_limit(2) end end diff --git a/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb index 927476cc655..136027736c3 100644 --- a/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb +++ b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Graphql::Loaders::PipelineForShaLoader do pipeline2 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha) pipeline3 = create(:ci_pipeline, project: project, ref: 'improve/awesome', sha: project.commit('improve/awesome').sha) - result = batch(max_queries: 1) do + result = batch_sync(max_queries: 1) do [pipeline1.sha, pipeline3.sha].map { |sha| described_class.new(project, sha).find_last } end diff --git a/spec/lib/gitlab/graphql/markdown_field_spec.rb b/spec/lib/gitlab/graphql/markdown_field_spec.rb index a8566aa8e1c..866a20801d3 100644 --- a/spec/lib/gitlab/graphql/markdown_field_spec.rb +++ b/spec/lib/gitlab/graphql/markdown_field_spec.rb @@ -30,17 +30,20 @@ describe Gitlab::Graphql::MarkdownField do let(:note) { build(:note, note: '# Markdown!') } let(:thing_with_markdown) { double('markdown thing', object: note) } let(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' } + let(:query_type) { GraphQL::ObjectType.new } + let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)} + let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: nil, object: nil) } it 'renders markdown from the same property as the field name without the `_html` suffix' do field = class_with_markdown_field(:note_html, null: false).fields['noteHtml'] - expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown) + expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown) end it 'renders markdown from a specific property when a `method` argument is passed' do field = class_with_markdown_field(:test_html, null: false, method: :note).fields['testHtml'] - expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown) + expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown) end end end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 3c6b17c10ec..dafa4243145 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -23,9 +23,11 @@ issues: - epic_issue - epic - designs +- design_versions events: - author - project +- group - target - push_event_payload notes: @@ -62,6 +64,8 @@ milestone: - participants - events - boards +- milestone_release +- release snippets: - author - project @@ -72,6 +76,8 @@ releases: - author - project - links +- milestone_release +- milestone links: - release project_members: @@ -121,6 +127,8 @@ merge_requests: - blocks_as_blockee - blocking_merge_requests - blocked_merge_requests +external_pull_requests: +- project merge_request_diff: - merge_request - merge_request_diff_commits @@ -150,6 +158,7 @@ ci_pipelines: - pipeline_schedule - merge_requests_as_head_pipeline - merge_request +- external_pull_request - deployments - environments - chat_data @@ -397,6 +406,7 @@ project: - merge_trains - designs - project_aliases +- external_pull_requests award_emoji: - awardable - user @@ -483,3 +493,7 @@ lists: - milestone - board - label +- list_user_preferences +milestone_releases: +- milestone +- release diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index d6e1fbaa979..87be7857e67 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -396,6 +396,27 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do expect(project.lfs_enabled).to be_falsey end + + it 'overrides project feature access levels' do + access_level_keys = project.project_feature.attributes.keys.select { |a| a =~ /_access_level/ } + + # `pages_access_level` is not included, since it is not available in the public API + # and has a dependency on project's visibility level + # see ProjectFeature model + access_level_keys.delete('pages_access_level') + + disabled_access_levels = Hash[access_level_keys.collect { |item| [item, 'disabled'] }] + + project.create_import_data(data: { override_params: disabled_access_levels }) + + restored_project_json + + aggregate_failures do + access_level_keys.each do |key| + expect(project.public_send(key)).to eq(ProjectFeature::DISABLED) + end + end + end end context 'with a project that has a group' do @@ -491,6 +512,24 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do expect(Milestone.find_by_title('Group-level milestone').iid).to eq(2) end end + + context 'with external authorization classification labels' do + it 'converts empty external classification authorization labels to nil' do + project.create_import_data(data: { override_params: { external_authorization_classification_label: "" } }) + + restored_project_json + + expect(project.external_authorization_classification_label).to be_nil + end + + it 'preserves valid external classification authorization labels' do + project.create_import_data(data: { override_params: { external_authorization_classification_label: "foobar" } }) + + restored_project_json + + expect(project.external_authorization_classification_label).to eq("foobar") + end + end end describe '#restored_project' do diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index f0545176a90..e9750d23c53 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -33,6 +33,7 @@ Event: - target_type - target_id - project_id +- group_id - created_at - updated_at - action @@ -269,6 +270,7 @@ Ci::Pipeline: - protected - iid - merge_request_id +- external_pull_request_id Ci::Stage: - id - name @@ -328,6 +330,7 @@ CommitStatus: - failure_reason - scheduled_at - upstream_pipeline_id +- interruptible Ci::Variable: - id - project_id @@ -466,6 +469,7 @@ ProtectedBranch: - name - created_at - updated_at +- code_owner_approval_required ProtectedTag: - id - project_id @@ -712,3 +716,16 @@ List: - updated_at - milestone_id - user_id +ExternalPullRequest: +- id +- created_at +- updated_at +- project_id +- pull_request_iid +- status +- source_branch +- target_branch +- source_repository +- target_repository +- source_sha +- target_sha diff --git a/spec/lib/gitlab/internal_post_receive/response_spec.rb b/spec/lib/gitlab/internal_post_receive/response_spec.rb new file mode 100644 index 00000000000..f43762c9248 --- /dev/null +++ b/spec/lib/gitlab/internal_post_receive/response_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::InternalPostReceive::Response do + subject { described_class.new } + + describe '#add_merge_request_urls' do + context 'when there are urls_data' do + it 'adds a message for each merge request URL' do + urls_data = [ + { new_merge_request: false, branch_name: 'foo', url: 'http://example.com/foo/bar/merge_requests/1' }, + { new_merge_request: true, branch_name: 'bar', url: 'http://example.com/foo/bar/merge_requests/new?merge_request%5Bsource_branch%5D=bar' } + ] + + subject.add_merge_request_urls(urls_data) + + expected = [a_kind_of(described_class::Message), a_kind_of(described_class::Message)] + expect(subject.messages).to match(expected) + end + end + end + + describe '#add_merge_request_url' do + context 'when :new_merge_request is false' do + it 'adds a basic message to view the existing merge request' do + url_data = { new_merge_request: false, branch_name: 'foo', url: 'http://example.com/foo/bar/merge_requests/1' } + + subject.add_merge_request_url(url_data) + + message = <<~MESSAGE.strip + View merge request for foo: + http://example.com/foo/bar/merge_requests/1 + MESSAGE + + expect(subject.messages.first.message).to eq(message) + expect(subject.messages.first.type).to eq(:basic) + end + end + + context 'when :new_merge_request is true' do + it 'adds a basic message to create a new merge request' do + url_data = { new_merge_request: true, branch_name: 'bar', url: 'http://example.com/foo/bar/merge_requests/new?merge_request%5Bsource_branch%5D=bar' } + + subject.add_merge_request_url(url_data) + + message = <<~MESSAGE.strip + To create a merge request for bar, visit: + http://example.com/foo/bar/merge_requests/new?merge_request%5Bsource_branch%5D=bar + MESSAGE + + expect(subject.messages.first.message).to eq(message) + expect(subject.messages.first.type).to eq(:basic) + end + end + end + + describe '#add_basic_message' do + context 'when text is present' do + it 'adds a basic message' do + subject.add_basic_message('hello') + + expect(subject.messages.first.message).to eq('hello') + expect(subject.messages.first.type).to eq(:basic) + end + end + + context 'when text is blank' do + it 'does not add a message' do + subject.add_basic_message(' ') + + expect(subject.messages).to be_blank + end + end + end + + describe '#add_alert_message' do + context 'when text is present' do + it 'adds a alert message' do + subject.add_alert_message('hello') + + expect(subject.messages.first.message).to eq('hello') + expect(subject.messages.first.type).to eq(:alert) + end + end + + context 'when text is blank' do + it 'does not add a message' do + subject.add_alert_message(' ') + + expect(subject.messages).to be_blank + end + end + end + + describe '#reference_counter_decreased' do + context 'initially' do + it 'reference_counter_decreased is set to false' do + expect(subject.reference_counter_decreased).to eq(false) + end + end + end + + describe '#reference_counter_decreased=' do + context 'when the argument is truthy' do + it 'reference_counter_decreased is truthy' do + subject.reference_counter_decreased = true + + expect(subject.reference_counter_decreased).to be_truthy + end + end + + context 'when the argument is falsey' do + it 'reference_counter_decreased is falsey' do + subject.reference_counter_decreased = false + + expect(subject.reference_counter_decreased).to be_falsey + end + end + end +end diff --git a/spec/lib/gitlab/jwt_authenticatable_spec.rb b/spec/lib/gitlab/jwt_authenticatable_spec.rb new file mode 100644 index 00000000000..0c1c491b308 --- /dev/null +++ b/spec/lib/gitlab/jwt_authenticatable_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::JwtAuthenticatable do + let(:test_class) do + Class.new do + include Gitlab::JwtAuthenticatable + + def self.secret_path + Rails.root.join('tmp', 'tests', '.jwt_shared_secret') + end + end + end + + before do + begin + File.delete(test_class.secret_path) + rescue Errno::ENOENT + end + + test_class.write_secret + end + + describe '.secret' do + subject(:secret) { test_class.secret } + + it 'returns 32 bytes' do + expect(secret).to be_a(String) + expect(secret.length).to eq(32) + expect(secret.encoding).to eq(Encoding::ASCII_8BIT) + end + + it 'accepts a trailing newline' do + File.open(test_class.secret_path, 'a') { |f| f.write "\n" } + + expect(secret.length).to eq(32) + end + + it 'raises an exception if the secret file cannot be read' do + File.delete(test_class.secret_path) + + expect { secret }.to raise_exception(Errno::ENOENT) + end + + it 'raises an exception if the secret file contains the wrong number of bytes' do + File.truncate(test_class.secret_path, 0) + + expect { secret }.to raise_exception(RuntimeError) + end + end + + describe '.write_secret' do + it 'uses mode 0600' do + expect(File.stat(test_class.secret_path).mode & 0777).to eq(0600) + end + + it 'writes base64 data' do + bytes = Base64.strict_decode64(File.read(test_class.secret_path)) + + expect(bytes).not_to be_empty + end + end + + describe '.decode_jwt_for_issuer' do + let(:payload) { { 'iss' => 'test_issuer' } } + + it 'accepts a correct header' do + encoded_message = JWT.encode(payload, test_class.secret, 'HS256') + + expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.not_to raise_error + end + + it 'raises an error when the JWT is not signed' do + encoded_message = JWT.encode(payload, nil, 'none') + + expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError) + end + + it 'raises an error when the header is signed with the wrong secret' do + encoded_message = JWT.encode(payload, 'wrongsecret', 'HS256') + + expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError) + end + + it 'raises an error when the issuer is incorrect' do + payload['iss'] = 'somebody else' + encoded_message = JWT.encode(payload, test_class.secret, 'HS256') + + expect { test_class.decode_jwt_for_issuer('test_issuer', encoded_message) }.to raise_error(JWT::DecodeError) + end + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb index 7395b095454..f7f510f01db 100644 --- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' describe Gitlab::Kubernetes::Helm::InstallCommand do let(:files) { { 'ca.pem': 'some file content' } } diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb index fce2aded786..64cadcc011c 100644 --- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' describe Gitlab::Kubernetes::Helm::Pod do describe '#generate' do diff --git a/spec/lib/gitlab/kubernetes/kube_client_spec.rb b/spec/lib/gitlab/kubernetes/kube_client_spec.rb index f49d4e23e39..e5d688aa391 100644 --- a/spec/lib/gitlab/kubernetes/kube_client_spec.rb +++ b/spec/lib/gitlab/kubernetes/kube_client_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' describe Gitlab::Kubernetes::KubeClient do + include StubRequests include KubernetesHelpers let(:api_url) { 'https://kubernetes.example.com/prefix' } @@ -14,6 +15,17 @@ describe Gitlab::Kubernetes::KubeClient do stub_kubeclient_discover(api_url) end + def method_call(client, method_name) + case method_name + when /\A(get_|delete_)/ + client.public_send(method_name) + when /\A(create_|update_)/ + client.public_send(method_name, {}) + else + raise "Unknown method name #{method_name}" + end + end + shared_examples 'a Kubeclient' do it 'is a Kubeclient::Client' do is_expected.to be_an_instance_of Kubeclient::Client @@ -25,28 +37,30 @@ describe Gitlab::Kubernetes::KubeClient do end shared_examples 'redirection not allowed' do |method_name| - before do - redirect_url = 'https://not-under-our-control.example.com/api/v1/pods' + context 'api_url is redirected' do + before do + redirect_url = 'https://not-under-our-control.example.com/api/v1/pods' - stub_request(:get, %r{\A#{api_url}/}) - .to_return(status: 302, headers: { location: redirect_url }) + stub_request(:get, %r{\A#{api_url}/}) + .to_return(status: 302, headers: { location: redirect_url }) - stub_request(:get, redirect_url) - .to_return(status: 200, body: '{}') - end + stub_request(:get, redirect_url) + .to_return(status: 200, body: '{}') + end - it 'does not follow redirects' do - method_call = -> do - case method_name - when /\A(get_|delete_)/ - client.public_send(method_name) - when /\A(create_|update_)/ - client.public_send(method_name, {}) - else - raise "Unknown method name #{method_name}" - end + it 'does not follow redirects' do + expect { method_call(client, method_name) }.to raise_error(Kubeclient::HttpError) end - expect { method_call.call }.to raise_error(Kubeclient::HttpError) + end + end + + shared_examples 'dns rebinding not allowed' do |method_name| + it 'does not allow DNS rebinding' do + stub_dns(api_url, ip_address: '8.8.8.8') + client + + stub_dns(api_url, ip_address: '192.168.2.120') + expect { method_call(client, method_name) }.to raise_error(ArgumentError, /is blocked/) end end @@ -160,6 +174,7 @@ describe Gitlab::Kubernetes::KubeClient do ].each do |method| describe "##{method}" do include_examples 'redirection not allowed', method + include_examples 'dns rebinding not allowed', method it 'delegates to the core client' do expect(client).to delegate_method(method).to(:core_client) @@ -185,6 +200,7 @@ describe Gitlab::Kubernetes::KubeClient do ].each do |method| describe "##{method}" do include_examples 'redirection not allowed', method + include_examples 'dns rebinding not allowed', method it 'delegates to the rbac client' do expect(client).to delegate_method(method).to(:rbac_client) @@ -203,6 +219,7 @@ describe Gitlab::Kubernetes::KubeClient do describe '#get_deployments' do include_examples 'redirection not allowed', 'get_deployments' + include_examples 'dns rebinding not allowed', 'get_deployments' it 'delegates to the extensions client' do expect(client).to delegate_method(:get_deployments).to(:extensions_client) diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index e70fde09edd..45e74597a2e 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -204,17 +204,17 @@ describe Gitlab::Metrics::Transaction do end it 'allows tracking of custom tags' do - transaction.add_event(:meow, animal: 'cat') + transaction.add_event(:bau, animal: 'dog') - expect(metric.tags).to eq(event: :meow, animal: 'cat') + expect(metric.tags).to eq(event: :bau, animal: 'dog') end context 'with sensitive tags' do before do - transaction.add_event(:meow, **sensitive_tags.merge(sane: 'yes')) + transaction.add_event(:baubau, **sensitive_tags.merge(sane: 'yes')) end - it_behaves_like 'tag filter', event: :meow, sane: 'yes' + it_behaves_like 'tag filter', event: :baubau, sane: 'yes' end end diff --git a/spec/lib/gitlab/metrics/web_transaction_spec.rb b/spec/lib/gitlab/metrics/web_transaction_spec.rb index 2b35f07cc0d..21a762dbf25 100644 --- a/spec/lib/gitlab/metrics/web_transaction_spec.rb +++ b/spec/lib/gitlab/metrics/web_transaction_spec.rb @@ -253,11 +253,11 @@ describe Gitlab::Metrics::WebTransaction do end it 'allows tracking of custom tags' do - transaction.add_event(:meow, animal: 'cat') + transaction.add_event(:bau, animal: 'dog') metric = transaction.metrics[0] - expect(metric.tags).to eq(event: :meow, animal: 'cat') + expect(metric.tags).to eq(event: :bau, animal: 'dog') end end end diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb index f52095bf633..16595102375 100644 --- a/spec/lib/gitlab/middleware/go_spec.rb +++ b/spec/lib/gitlab/middleware/go_spec.rb @@ -202,7 +202,7 @@ describe Gitlab::Middleware::Go do def expect_response_with_path(response, protocol, path) repository_url = case protocol when :ssh - "ssh://git@#{Gitlab.config.gitlab.host}/#{path}.git" + "ssh://#{Gitlab.config.gitlab.user}@#{Gitlab.config.gitlab.host}/#{path}.git" when :http, nil "http://#{Gitlab.config.gitlab.host}/#{path}.git" end diff --git a/spec/lib/gitlab/patch/chronic_duration_spec.rb b/spec/lib/gitlab/patch/chronic_duration_spec.rb new file mode 100644 index 00000000000..541037ec1a2 --- /dev/null +++ b/spec/lib/gitlab/patch/chronic_duration_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Patch::ChronicDuration do + subject { ChronicDuration.parse('1mo') } + + it 'uses default conversions' do + expect(subject).to eq(2_592_000) + end + + context 'with custom conversions' do + before do + ChronicDuration.hours_per_day = 8 + ChronicDuration.days_per_week = 5 + end + + after do + ChronicDuration.hours_per_day = 24 + ChronicDuration.days_per_week = 7 + end + + it 'uses custom conversions' do + expect(subject).to eq(576_000) + end + end +end diff --git a/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb b/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb new file mode 100644 index 00000000000..3b92261f0fe --- /dev/null +++ b/spec/lib/gitlab/performance_bar/with_top_level_warnings_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rspec-parameterized' + +describe Gitlab::PerformanceBar::WithTopLevelWarnings do + using RSpec::Parameterized::TableSyntax + + subject { Module.new } + + before do + subject.singleton_class.prepend(described_class) + end + + describe '#has_warnings?' do + where(:has_warnings, :results) do + false | { data: {} } + false | { data: { gitaly: { warnings: [] } } } + true | { data: { gitaly: { warnings: [1] } } } + true | { data: { gitaly: { warnings: [] }, redis: { warnings: [1] } } } + end + + with_them do + it do + expect(subject.has_warnings?(results)).to eq(has_warnings) + end + end + end +end diff --git a/spec/lib/gitlab/performance_bar_spec.rb b/spec/lib/gitlab/performance_bar_spec.rb index 8d8ac2aebbe..816db49d94a 100644 --- a/spec/lib/gitlab/performance_bar_spec.rb +++ b/spec/lib/gitlab/performance_bar_spec.rb @@ -6,14 +6,14 @@ describe Gitlab::PerformanceBar do shared_examples 'allowed user IDs are cached' do before do # Warm the caches - described_class.enabled?(user) + described_class.enabled_for_user?(user) end it 'caches the allowed user IDs in cache', :use_clean_rails_memory_store_caching do expect do expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original expect(described_class.l2_cache_backend).not_to receive(:fetch) - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end.not_to exceed_query_limit(0) end @@ -22,7 +22,7 @@ describe Gitlab::PerformanceBar do expect do expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original expect(described_class.l2_cache_backend).to receive(:fetch).and_call_original - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end.not_to exceed_query_limit(0) end end @@ -32,7 +32,7 @@ describe Gitlab::PerformanceBar do expect do expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original expect(described_class.l2_cache_backend).to receive(:fetch).and_call_original - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end.not_to exceed_query_limit(2) end end @@ -41,7 +41,7 @@ describe Gitlab::PerformanceBar do it { expect(described_class.l1_cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend) } it { expect(described_class.l2_cache_backend).to eq(Rails.cache) } - describe '.enabled?' do + describe '.enabled_for_user?' do let(:user) { create(:user) } before do @@ -49,24 +49,24 @@ describe Gitlab::PerformanceBar do end it 'returns false when given user is nil' do - expect(described_class.enabled?(nil)).to be_falsy + expect(described_class.enabled_for_user?(nil)).to be_falsy end it 'returns true when given user is an admin' do user = build_stubbed(:user, :admin) - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end it 'returns false when allowed_group_id is nil' do expect(described_class).to receive(:allowed_group_id).and_return(nil) - expect(described_class.enabled?(user)).to be_falsy + expect(described_class.enabled_for_user?(user)).to be_falsy end context 'when allowed group ID does not exist' do it 'returns false' do - expect(described_class.enabled?(user)).to be_falsy + expect(described_class.enabled_for_user?(user)).to be_falsy end end @@ -79,7 +79,7 @@ describe Gitlab::PerformanceBar do context 'when user is not a member of the allowed group' do it 'returns false' do - expect(described_class.enabled?(user)).to be_falsy + expect(described_class.enabled_for_user?(user)).to be_falsy end it_behaves_like 'allowed user IDs are cached' @@ -91,7 +91,7 @@ describe Gitlab::PerformanceBar do end it 'returns true' do - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end it_behaves_like 'allowed user IDs are cached' @@ -108,7 +108,7 @@ describe Gitlab::PerformanceBar do end it 'returns the nested group' do - expect(described_class.enabled?(user)).to be_truthy + expect(described_class.enabled_for_user?(user)).to be_truthy end end @@ -118,7 +118,7 @@ describe Gitlab::PerformanceBar do end it 'returns false' do - expect(described_class.enabled?(user)).to be_falsy + expect(described_class.enabled_for_user?(user)).to be_falsy end end end diff --git a/spec/lib/gitlab/prometheus/metric_group_spec.rb b/spec/lib/gitlab/prometheus/metric_group_spec.rb index a45dd0af91e..787f14daf47 100644 --- a/spec/lib/gitlab/prometheus/metric_group_spec.rb +++ b/spec/lib/gitlab/prometheus/metric_group_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::Prometheus::MetricGroup do describe '.common_metrics' do diff --git a/spec/lib/gitlab/query_limiting/transaction_spec.rb b/spec/lib/gitlab/query_limiting/transaction_spec.rb index 39d5a575efc..4e906314b5a 100644 --- a/spec/lib/gitlab/query_limiting/transaction_spec.rb +++ b/spec/lib/gitlab/query_limiting/transaction_spec.rb @@ -86,9 +86,7 @@ describe Gitlab::QueryLimiting::Transaction do it 'returns false in a production environment' do transaction = described_class.new - expect(Rails.env) - .to receive(:test?) - .and_return(false) + stub_rails_env('production') expect(transaction.raise_error?).to eq(false) end diff --git a/spec/lib/gitlab/query_limiting_spec.rb b/spec/lib/gitlab/query_limiting_spec.rb index f0d0340cd6e..e9c6bbc35a3 100644 --- a/spec/lib/gitlab/query_limiting_spec.rb +++ b/spec/lib/gitlab/query_limiting_spec.rb @@ -9,14 +9,14 @@ describe Gitlab::QueryLimiting do end it 'returns true in a development environment' do - allow(Rails.env).to receive(:development?).and_return(true) + stub_rails_env('development') + stub_rails_env('development') expect(described_class.enable?).to eq(true) end it 'returns false on GitLab.com' do - expect(Rails.env).to receive(:development?).and_return(false) - expect(Rails.env).to receive(:test?).and_return(false) + stub_rails_env('production') allow(Gitlab).to receive(:com?).and_return(true) expect(described_class.enable?).to eq(false) @@ -24,8 +24,7 @@ describe Gitlab::QueryLimiting do it 'returns false in a non GitLab.com' do allow(Gitlab).to receive(:com?).and_return(false) - expect(Rails.env).to receive(:development?).and_return(false) - expect(Rails.env).to receive(:test?).and_return(false) + stub_rails_env('production') expect(described_class.enable?).to eq(false) end diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb index fd1338b55a6..808eb865a21 100644 --- a/spec/lib/gitlab/repository_cache_adapter_spec.rb +++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb @@ -6,7 +6,6 @@ describe Gitlab::RepositoryCacheAdapter do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:cache) { repository.send(:cache) } - let(:redis_set_cache) { repository.send(:redis_set_cache) } describe '#cache_method_output', :use_clean_rails_memory_store_caching do let(:fallback) { 10 } @@ -209,11 +208,9 @@ describe Gitlab::RepositoryCacheAdapter do describe '#expire_method_caches' do it 'expires the caches of the given methods' do expect(cache).to receive(:expire).with(:rendered_readme) - expect(cache).to receive(:expire).with(:branch_names) - expect(redis_set_cache).to receive(:expire).with(:rendered_readme) - expect(redis_set_cache).to receive(:expire).with(:branch_names) + expect(cache).to receive(:expire).with(:gitignore) - repository.expire_method_caches(%i(rendered_readme branch_names)) + repository.expire_method_caches(%i(rendered_readme gitignore)) end it 'does not expire caches for non-existent methods' do diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb deleted file mode 100644 index 87e51f801e5..00000000000 --- a/spec/lib/gitlab/repository_set_cache_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::RepositorySetCache, :clean_gitlab_redis_cache do - let(:project) { create(:project) } - let(:repository) { project.repository } - let(:namespace) { "#{repository.full_path}:#{project.id}" } - let(:cache) { described_class.new(repository) } - - describe '#cache_key' do - subject { cache.cache_key(:foo) } - - it 'includes the namespace' do - is_expected.to eq("foo:#{namespace}:set") - end - - context 'with a given namespace' do - let(:extra_namespace) { 'my:data' } - let(:cache) { described_class.new(repository, extra_namespace: extra_namespace) } - - it 'includes the full namespace' do - is_expected.to eq("foo:#{namespace}:#{extra_namespace}:set") - end - end - end - - describe '#expire' do - it 'expires the given key from the cache' do - cache.write(:foo, ['value']) - - expect(cache.read(:foo)).to contain_exactly('value') - expect(cache.expire(:foo)).to eq(1) - expect(cache.read(:foo)).to be_empty - end - end - - describe '#exist?' do - it 'checks whether the key exists' do - expect(cache.exist?(:foo)).to be(false) - - cache.write(:foo, ['value']) - - expect(cache.exist?(:foo)).to be(true) - end - end - - describe '#fetch' do - let(:blk) { -> { ['block value'] } } - - subject { cache.fetch(:foo, &blk) } - - it 'fetches the key from the cache when filled' do - cache.write(:foo, ['value']) - - is_expected.to contain_exactly('value') - end - - it 'writes the value of the provided block when empty' do - cache.expire(:foo) - - is_expected.to contain_exactly('block value') - expect(cache.read(:foo)).to contain_exactly('block value') - end - end - - describe '#include?' do - it 'checks inclusion in the Redis set' do - cache.write(:foo, ['value']) - - expect(cache.include?(:foo, 'value')).to be(true) - expect(cache.include?(:foo, 'bar')).to be(false) - end - end -end diff --git a/spec/lib/gitlab/sanitizers/exif_spec.rb b/spec/lib/gitlab/sanitizers/exif_spec.rb index 22c5f27dc6d..f882dbbdb5c 100644 --- a/spec/lib/gitlab/sanitizers/exif_spec.rb +++ b/spec/lib/gitlab/sanitizers/exif_spec.rb @@ -7,7 +7,9 @@ describe Gitlab::Sanitizers::Exif do describe '#batch_clean' do context 'with image uploads' do - let!(:uploads) { create_list(:upload, 3, :with_file, :issuable_upload) } + set(:upload1) { create(:upload, :with_file, :issuable_upload) } + set(:upload2) { create(:upload, :with_file, :personal_snippet_upload) } + set(:upload3) { create(:upload, :with_file, created_at: 3.days.ago) } it 'processes all uploads if range ID is not set' do expect(sanitizer).to receive(:clean).exactly(3).times @@ -18,7 +20,19 @@ describe Gitlab::Sanitizers::Exif do it 'processes only uploads in the selected range' do expect(sanitizer).to receive(:clean).once - sanitizer.batch_clean(start_id: uploads[1].id, stop_id: uploads[1].id) + sanitizer.batch_clean(start_id: upload1.id, stop_id: upload1.id) + end + + it 'processes only uploads for the selected uploader' do + expect(sanitizer).to receive(:clean).once + + sanitizer.batch_clean(uploader: 'PersonalFileUploader') + end + + it 'processes only uploads created since specified date' do + expect(sanitizer).to receive(:clean).exactly(2).times + + sanitizer.batch_clean(since: 2.days.ago) end it 'pauses if sleep_time is set' do diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 0ba16b93ee7..fe4853fd819 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -52,38 +52,14 @@ describe Gitlab::Shell do describe '#add_key' do context 'when authorized_keys_enabled is true' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls #gitlab_shell_fast_execute with add-key command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([ - :gitlab_shell_keys_path, - 'add-key', - 'key-123', - 'ssh-rsa foobar' - ]) - - gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') - end - end - - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#add_key with id and key' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + it 'calls Gitlab::AuthorizedKeys#add_key with id and key' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys) - .to receive(:add_key) - .with('key-123', 'ssh-rsa foobar') + expect(gitlab_authorized_keys) + .to receive(:add_key) + .with('key-123', 'ssh-rsa foobar') - gitlab_shell.add_key('key-123', 'ssh-rsa foobar') - end + gitlab_shell.add_key('key-123', 'ssh-rsa foobar') end end @@ -92,24 +68,10 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: false) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - end + it 'does nothing' do + expect(Gitlab::AuthorizedKeys).not_to receive(:new) - it 'does nothing' do - expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute) - - gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') - end - end - - context 'authorized_keys_file set' do - it 'does nothing' do - expect(Gitlab::AuthorizedKeys).not_to receive(:new) - - gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') - end + gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') end end @@ -118,38 +80,14 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: nil) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls #gitlab_shell_fast_execute with add-key command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([ - :gitlab_shell_keys_path, - 'add-key', - 'key-123', - 'ssh-rsa foobar' - ]) - - gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage') - end - end - - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#add_key with id and key' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + it 'calls Gitlab::AuthorizedKeys#add_key with id and key' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys) - .to receive(:add_key) - .with('key-123', 'ssh-rsa foobar') + expect(gitlab_authorized_keys) + .to receive(:add_key) + .with('key-123', 'ssh-rsa foobar') - gitlab_shell.add_key('key-123', 'ssh-rsa foobar') - end + gitlab_shell.add_key('key-123', 'ssh-rsa foobar') end end end @@ -158,50 +96,14 @@ describe Gitlab::Shell do let(:keys) { [double(shell_id: 'key-123', key: 'ssh-rsa foobar')] } context 'when authorized_keys_enabled is true' do - context 'authorized_keys_file not set' do - let(:io) { double } - - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - end - - context 'valid keys' do - before do - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls gitlab-keys with batch-add-keys command' do - expect(IO) - .to receive(:popen) - .with("gitlab_shell_keys_path batch-add-keys", 'w') - .and_yield(io) - - expect(io).to receive(:puts).with("key-123\tssh-rsa foobar") - expect(gitlab_shell.batch_add_keys(keys)).to be_truthy - end - end - - context 'invalid keys' do - let(:keys) { [double(shell_id: 'key-123', key: "ssh-rsa A\tSDFA\nSGADG")] } - - it 'catches failure and returns false' do - expect(gitlab_shell.batch_add_keys(keys)).to be_falsey - end - end - end + it 'calls Gitlab::AuthorizedKeys#batch_add_keys with keys to be added' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#batch_add_keys with keys to be added' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + expect(gitlab_authorized_keys) + .to receive(:batch_add_keys) + .with(keys) - expect(gitlab_authorized_keys) - .to receive(:batch_add_keys) - .with(keys) - - gitlab_shell.batch_add_keys(keys) - end + gitlab_shell.batch_add_keys(keys) end end @@ -210,24 +112,10 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: false) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - end - - it 'does nothing' do - expect(IO).not_to receive(:popen) - - gitlab_shell.batch_add_keys(keys) - end - end - - context 'authorized_keys_file set' do - it 'does nothing' do - expect(Gitlab::AuthorizedKeys).not_to receive(:new) + it 'does nothing' do + expect(Gitlab::AuthorizedKeys).not_to receive(:new) - gitlab_shell.batch_add_keys(keys) - end + gitlab_shell.batch_add_keys(keys) end end @@ -236,72 +124,25 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: nil) end - context 'authorized_keys_file not set' do - let(:io) { double } + it 'calls Gitlab::AuthorizedKeys#batch_add_keys with keys to be added' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls gitlab-keys with batch-add-keys command' do - expect(IO) - .to receive(:popen) - .with("gitlab_shell_keys_path batch-add-keys", 'w') - .and_yield(io) + expect(gitlab_authorized_keys) + .to receive(:batch_add_keys) + .with(keys) - expect(io).to receive(:puts).with("key-123\tssh-rsa foobar") - - gitlab_shell.batch_add_keys(keys) - end - end - - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#batch_add_keys with keys to be added' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - - expect(gitlab_authorized_keys) - .to receive(:batch_add_keys) - .with(keys) - - gitlab_shell.batch_add_keys(keys) - end + gitlab_shell.batch_add_keys(keys) end end end describe '#remove_key' do context 'when authorized_keys_enabled is true' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls #gitlab_shell_fast_execute with rm-key command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([ - :gitlab_shell_keys_path, - 'rm-key', - 'key-123' - ]) - - gitlab_shell.remove_key('key-123') - end - end + it 'calls Gitlab::AuthorizedKeys#rm_key with the key to be removed' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + expect(gitlab_authorized_keys).to receive(:rm_key).with('key-123') - context 'authorized_keys_file not set' do - it 'calls Gitlab::AuthorizedKeys#rm_key with the key to be removed' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys).to receive(:rm_key).with('key-123') - - gitlab_shell.remove_key('key-123') - end + gitlab_shell.remove_key('key-123') end end @@ -310,24 +151,10 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: false) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - end - - it 'does nothing' do - expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute) + it 'does nothing' do + expect(Gitlab::AuthorizedKeys).not_to receive(:new) - gitlab_shell.remove_key('key-123') - end - end - - context 'authorized_keys_file set' do - it 'does nothing' do - expect(Gitlab::AuthorizedKeys).not_to receive(:new) - - gitlab_shell.remove_key('key-123') - end + gitlab_shell.remove_key('key-123') end end @@ -336,64 +163,22 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: nil) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls #gitlab_shell_fast_execute with rm-key command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([ - :gitlab_shell_keys_path, - 'rm-key', - 'key-123' - ]) - - gitlab_shell.remove_key('key-123') - end - end - - context 'authorized_keys_file not set' do - it 'calls Gitlab::AuthorizedKeys#rm_key with the key to be removed' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys).to receive(:rm_key).with('key-123') + it 'calls Gitlab::AuthorizedKeys#rm_key with the key to be removed' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + expect(gitlab_authorized_keys).to receive(:rm_key).with('key-123') - gitlab_shell.remove_key('key-123') - end + gitlab_shell.remove_key('key-123') end end end describe '#remove_all_keys' do context 'when authorized_keys_enabled is true' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end + it 'calls Gitlab::AuthorizedKeys#clear' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + expect(gitlab_authorized_keys).to receive(:clear) - it 'calls #gitlab_shell_fast_execute with clear command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([:gitlab_shell_keys_path, 'clear']) - - gitlab_shell.remove_all_keys - end - end - - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#clear' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys).to receive(:clear) - - gitlab_shell.remove_all_keys - end + gitlab_shell.remove_all_keys end end @@ -402,24 +187,10 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: false) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - end - - it 'does nothing' do - expect(gitlab_shell).not_to receive(:gitlab_shell_fast_execute) + it 'does nothing' do + expect(Gitlab::AuthorizedKeys).not_to receive(:new) - gitlab_shell.remove_all_keys - end - end - - context 'authorized_keys_file set' do - it 'does nothing' do - expect(Gitlab::AuthorizedKeys).not_to receive(:new) - - gitlab_shell.remove_all_keys - end + gitlab_shell.remove_all_keys end end @@ -428,163 +199,73 @@ describe Gitlab::Shell do stub_application_setting(authorized_keys_enabled: nil) end - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - allow(gitlab_shell) - .to receive(:gitlab_shell_keys_path) - .and_return(:gitlab_shell_keys_path) - end - - it 'calls #gitlab_shell_fast_execute with clear command' do - expect(gitlab_shell) - .to receive(:gitlab_shell_fast_execute) - .with([:gitlab_shell_keys_path, 'clear']) + it 'calls Gitlab::AuthorizedKeys#clear' do + expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) + expect(gitlab_authorized_keys).to receive(:clear) - gitlab_shell.remove_all_keys - end - end - - context 'authorized_keys_file set' do - it 'calls Gitlab::AuthorizedKeys#clear' do - expect(Gitlab::AuthorizedKeys).to receive(:new).and_return(gitlab_authorized_keys) - expect(gitlab_authorized_keys).to receive(:clear) - - gitlab_shell.remove_all_keys - end + gitlab_shell.remove_all_keys end end end describe '#remove_keys_not_found_in_db' do context 'when keys are in the file that are not in the DB' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - gitlab_shell.remove_all_keys - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - gitlab_shell.add_key('key-9876', 'ssh-rsa ASDFASDF') - @another_key = create(:key) # this one IS in the DB - end - - it 'removes the keys' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') - expect(gitlab_shell).to receive(:remove_key).with('key-9876') - expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@another_key.id}") - - gitlab_shell.remove_keys_not_found_in_db - end + before do + gitlab_shell.remove_all_keys + gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') + gitlab_shell.add_key('key-9876', 'ssh-rsa ASDFASDF') + @another_key = create(:key) # this one IS in the DB end - context 'authorized_keys_file set' do - before do - gitlab_shell.remove_all_keys - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - gitlab_shell.add_key('key-9876', 'ssh-rsa ASDFASDF') - @another_key = create(:key) # this one IS in the DB - end - - it 'removes the keys' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') - expect(gitlab_shell).to receive(:remove_key).with('key-9876') - expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@another_key.id}") + it 'removes the keys' do + expect(gitlab_shell).to receive(:remove_key).with('key-1234') + expect(gitlab_shell).to receive(:remove_key).with('key-9876') + expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@another_key.id}") - gitlab_shell.remove_keys_not_found_in_db - end + gitlab_shell.remove_keys_not_found_in_db end end context 'when keys there are duplicate keys in the file that are not in the DB' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - gitlab_shell.remove_all_keys - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - end - - it 'removes the keys' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') - - gitlab_shell.remove_keys_not_found_in_db - end + before do + gitlab_shell.remove_all_keys + gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') + gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') end - context 'authorized_keys_file set' do - before do - gitlab_shell.remove_all_keys - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - end - - it 'removes the keys' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') + it 'removes the keys' do + expect(gitlab_shell).to receive(:remove_key).with('key-1234') - gitlab_shell.remove_keys_not_found_in_db - end + gitlab_shell.remove_keys_not_found_in_db end end context 'when keys there are duplicate keys in the file that ARE in the DB' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - gitlab_shell.remove_all_keys - @key = create(:key) - gitlab_shell.add_key(@key.shell_id, @key.key) - end - - it 'does not remove the key' do - expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@key.id}") - - gitlab_shell.remove_keys_not_found_in_db - end + before do + gitlab_shell.remove_all_keys + @key = create(:key) + gitlab_shell.add_key(@key.shell_id, @key.key) end - context 'authorized_keys_file set' do - before do - gitlab_shell.remove_all_keys - @key = create(:key) - gitlab_shell.add_key(@key.shell_id, @key.key) - end - - it 'does not remove the key' do - expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@key.id}") + it 'does not remove the key' do + expect(gitlab_shell).not_to receive(:remove_key).with("key-#{@key.id}") - gitlab_shell.remove_keys_not_found_in_db - end + gitlab_shell.remove_keys_not_found_in_db end end unless ENV['CI'] # Skip in CI, it takes 1 minute context 'when the first batch can be skipped, but the next batch has keys that are not in the DB' do - context 'authorized_keys_file not set' do - before do - stub_gitlab_shell_setting(authorized_keys_file: nil) - gitlab_shell.remove_all_keys - 100.times { |i| create(:key) } # first batch is all in the DB - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - end - - it 'removes the keys not in the DB' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') - - gitlab_shell.remove_keys_not_found_in_db - end + before do + gitlab_shell.remove_all_keys + 100.times { |i| create(:key) } # first batch is all in the DB + gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') end - context 'authorized_keys_file set' do - before do - gitlab_shell.remove_all_keys - 100.times { |i| create(:key) } # first batch is all in the DB - gitlab_shell.add_key('key-1234', 'ssh-rsa ASDFASDF') - end - - it 'removes the keys not in the DB' do - expect(gitlab_shell).to receive(:remove_key).with('key-1234') + it 'removes the keys not in the DB' do + expect(gitlab_shell).to receive(:remove_key).with('key-1234') - gitlab_shell.remove_keys_not_found_in_db - end + gitlab_shell.remove_keys_not_found_in_db end end end diff --git a/spec/lib/gitlab/sidekiq_config_spec.rb b/spec/lib/gitlab/sidekiq_config_spec.rb index 1e8ccb447b1..49efbac160a 100644 --- a/spec/lib/gitlab/sidekiq_config_spec.rb +++ b/spec/lib/gitlab/sidekiq_config_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rails_helper' +require 'spec_helper' describe Gitlab::SidekiqConfig do describe '.workers' do diff --git a/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb index e430599bd94..ac97a5ebd15 100644 --- a/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb +++ b/spec/lib/gitlab/sidekiq_middleware/metrics_spec.rb @@ -13,7 +13,7 @@ describe Gitlab::SidekiqMiddleware::Metrics do let(:running_jobs_metric) { double('running jobs metric') } before do - allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything, anything).and_return(completion_seconds_metric) + allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_completion_seconds, anything, anything, anything).and_return(completion_seconds_metric) allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_failed_total, anything).and_return(failed_total_metric) allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_retried_total, anything).and_return(retried_total_metric) allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_running_jobs, anything, {}, :livesum).and_return(running_jobs_metric) diff --git a/spec/lib/gitlab/slash_commands/application_help_spec.rb b/spec/lib/gitlab/slash_commands/application_help_spec.rb index b203a1ee79c..afa63c21584 100644 --- a/spec/lib/gitlab/slash_commands/application_help_spec.rb +++ b/spec/lib/gitlab/slash_commands/application_help_spec.rb @@ -4,10 +4,11 @@ require 'spec_helper' describe Gitlab::SlashCommands::ApplicationHelp do let(:params) { { command: '/gitlab', text: 'help' } } + let(:project) { build(:project) } describe '#execute' do subject do - described_class.new(params).execute + described_class.new(project, params).execute end it 'displays the help section' do diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index c4ea8cbf2b1..dc412c80e68 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::SlashCommands::Command do it 'displays the help message' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Unknown command') + expect(subject[:text]).to start_with('The specified command is not valid') expect(subject[:text]).to match('/gitlab issue show') end end @@ -37,7 +37,7 @@ describe Gitlab::SlashCommands::Command do it 'rejects the actions' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! This action is not allowed') + expect(subject[:text]).to start_with('You are not allowed') end end @@ -57,7 +57,7 @@ describe Gitlab::SlashCommands::Command do context 'and user can not create deployment' do it 'returns action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! This action is not allowed') + expect(subject[:text]).to start_with('You are not allowed') end end diff --git a/spec/lib/gitlab/slash_commands/issue_close_spec.rb b/spec/lib/gitlab/slash_commands/issue_close_spec.rb new file mode 100644 index 00000000000..c0760ce0ba6 --- /dev/null +++ b/spec/lib/gitlab/slash_commands/issue_close_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SlashCommands::IssueClose do + describe '#execute' do + let(:issue) { create(:issue, project: project) } + let(:project) { create(:project) } + let(:user) { issue.author } + let(:chat_name) { double(:chat_name, user: user) } + let(:regex_match) { described_class.match("issue close #{issue.iid}") } + + subject do + described_class.new(project, chat_name).execute(regex_match) + end + + context 'when the user does not have permission' do + let(:chat_name) { double(:chat_name, user: create(:user)) } + + it 'does not allow the user to close the issue' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("not found") + expect(issue.reload).to be_open + end + end + + context 'the issue exists' do + let(:title) { subject[:attachments].first[:title] } + + it 'closes and returns the issue' do + expect(subject[:response_type]).to be(:in_channel) + expect(issue.reload).to be_closed + expect(title).to start_with(issue.title) + end + + context 'when its reference is given' do + let(:regex_match) { described_class.match("issue close #{issue.to_reference}") } + + it 'closes and returns the issue' do + expect(subject[:response_type]).to be(:in_channel) + expect(issue.reload).to be_closed + expect(title).to start_with(issue.title) + end + end + end + + context 'the issue does not exist' do + let(:regex_match) { described_class.match("issue close 2343242") } + + it "returns not found" do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("not found") + end + end + + context 'when the issue is already closed' do + let(:issue) { create(:issue, :closed, project: project) } + + it 'shows the issue' do + expect(subject[:response_type]).to be(:ephemeral) + expect(issue.reload).to be_closed + expect(subject[:text]).to match("already closed") + end + end + end + + describe '.match' do + it 'matches the iid' do + match = described_class.match("issue close 123") + + expect(match[:iid]).to eq("123") + end + + it 'accepts a reference' do + match = described_class.match("issue close #{Issue.reference_prefix}123") + + expect(match[:iid]).to eq("123") + end + end +end diff --git a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb index 286fec892e6..f00039c634f 100644 --- a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb @@ -4,12 +4,14 @@ require 'spec_helper' describe Gitlab::SlashCommands::Presenters::Access do describe '#access_denied' do - subject { described_class.new.access_denied } + let(:project) { build(:project) } + + subject { described_class.new.access_denied(project) } it { is_expected.to be_a(Hash) } it 'displays an error message' do - expect(subject[:text]).to match("is not allowed") + expect(subject[:text]).to match('are not allowed') expect(subject[:response_type]).to be(:ephemeral) end end diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_close_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_close_spec.rb new file mode 100644 index 00000000000..adc13b4ee56 --- /dev/null +++ b/spec/lib/gitlab/slash_commands/presenters/issue_close_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::SlashCommands::Presenters::IssueClose do + let(:project) { create(:project) } + let(:issue) { create(:issue, project: project) } + let(:attachment) { subject[:attachments].first } + + subject { described_class.new(issue).present } + + it { is_expected.to be_a(Hash) } + + it 'shows the issue' do + expect(subject[:response_type]).to be(:in_channel) + expect(subject).to have_key(:attachments) + expect(attachment[:title]).to start_with(issue.title) + end + + context 'confidential issue' do + let(:issue) { create(:issue, :confidential, project: project) } + + it 'shows an ephemeral response' do + expect(subject[:response_type]).to be(:ephemeral) + end + end +end diff --git a/spec/lib/gitlab/snowplow_tracker_spec.rb b/spec/lib/gitlab/snowplow_tracker_spec.rb deleted file mode 100644 index 073a33e5973..00000000000 --- a/spec/lib/gitlab/snowplow_tracker_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' - -describe Gitlab::SnowplowTracker do - let(:timestamp) { Time.utc(2017, 3, 22) } - - around do |example| - Timecop.freeze(timestamp) { example.run } - end - - subject { described_class.track_event('epics', 'action', property: 'what', value: 'doit') } - - context '.track_event' do - context 'when Snowplow tracker is disabled' do - it 'does not track the event' do - expect(SnowplowTracker::Tracker).not_to receive(:new) - - subject - end - end - - context 'when Snowplow tracker is enabled' do - before do - stub_application_setting(snowplow_enabled: true) - stub_application_setting(snowplow_site_id: 'awesome gitlab') - stub_application_setting(snowplow_collector_hostname: 'url.com') - end - - it 'tracks the event' do - tracker = double - - expect(::SnowplowTracker::Tracker).to receive(:new) - .with( - an_instance_of(::SnowplowTracker::Emitter), - an_instance_of(::SnowplowTracker::Subject), - 'cf', 'awesome gitlab' - ).and_return(tracker) - expect(tracker).to receive(:track_struct_event) - .with('epics', 'action', nil, 'what', 'doit', nil, timestamp.to_i) - - subject - end - end - end -end diff --git a/spec/lib/gitlab/time_tracking_formatter_spec.rb b/spec/lib/gitlab/time_tracking_formatter_spec.rb index a85d418777f..cfc804c13a7 100644 --- a/spec/lib/gitlab/time_tracking_formatter_spec.rb +++ b/spec/lib/gitlab/time_tracking_formatter_spec.rb @@ -17,6 +17,14 @@ describe Gitlab::TimeTrackingFormatter do it { expect(subject).to eq(-12_000) } end + + context 'durations with months' do + let(:duration_string) { '1mo' } + + it 'uses our custom conversions' do + expect(subject).to eq(576_000) + end + end end describe '#output' do diff --git a/spec/lib/gitlab/tracing_spec.rb b/spec/lib/gitlab/tracing_spec.rb index db75ce2a998..e913bb600ec 100644 --- a/spec/lib/gitlab/tracing_spec.rb +++ b/spec/lib/gitlab/tracing_spec.rb @@ -59,7 +59,7 @@ describe Gitlab::Tracing do it 'returns the correct state for .tracing_url' do expect(described_class).to receive(:tracing_url_enabled?).and_return(tracing_url_enabled?) allow(described_class).to receive(:tracing_url_template).and_return(tracing_url_template) - allow(Gitlab::CorrelationId).to receive(:current_id).and_return(correlation_id) + allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return(correlation_id) allow(Gitlab).to receive(:process_name).and_return(process_name) expect(described_class.tracing_url).to eq(tracing_url) diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb new file mode 100644 index 00000000000..f14e74427e1 --- /dev/null +++ b/spec/lib/gitlab/tracking_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Tracking do + let(:timestamp) { Time.utc(2017, 3, 22) } + + before do + stub_application_setting(snowplow_enabled: true) + stub_application_setting(snowplow_collector_hostname: 'gitfoo.com') + stub_application_setting(snowplow_cookie_domain: '.gitfoo.com') + stub_application_setting(snowplow_site_id: '_abc123_') + end + + describe '.snowplow_options' do + subject(&method(:described_class)) + + it 'returns useful client options' do + expect(subject.snowplow_options(nil)).to eq( + namespace: 'gl', + hostname: 'gitfoo.com', + cookieDomain: '.gitfoo.com', + appId: '_abc123_', + pageTrackingEnabled: true, + activityTrackingEnabled: true + ) + end + + it 'enables features using feature flags' do + stub_feature_flags(additional_snowplow_tracking: true) + allow(Feature).to receive(:enabled?).with( + :additional_snowplow_tracking, + '_group_' + ).and_return(false) + + expect(subject.snowplow_options('_group_')).to include( + pageTrackingEnabled: false, + activityTrackingEnabled: false + ) + end + end + + describe '.event' do + subject(&method(:described_class)) + + around do |example| + Timecop.freeze(timestamp) { example.run } + end + + it 'can track events' do + tracker = double + + expect(SnowplowTracker::Emitter).to receive(:new).with( + 'gitfoo.com' + ).and_return('_emitter_') + + expect(SnowplowTracker::Tracker).to receive(:new).with( + '_emitter_', + an_instance_of(SnowplowTracker::Subject), + 'gl', + '_abc123_' + ).and_return(tracker) + + expect(tracker).to receive(:track_struct_event).with( + 'category', + 'action', + '_label_', + '_property_', + '_value_', + '_context_', + timestamp.to_i + ) + + subject.event('category', 'action', + label: '_label_', + property: '_property_', + value: '_value_', + context: '_context_' + ) + end + + it 'does not track when not enabled' do + stub_application_setting(snowplow_enabled: false) + expect(SnowplowTracker::Tracker).not_to receive(:new) + + subject.event('epics', 'action', property: 'what', value: 'doit') + end + end +end diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index df8a1f82f81..6d1d7e48326 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -4,80 +4,114 @@ require 'spec_helper' describe Gitlab::UrlBlocker do + include StubRequests + describe '#validate!' do + subject { described_class.validate!(import_url) } + + shared_examples 'validates URI and hostname' do + it 'runs the url validations' do + uri, hostname = subject + + expect(uri).to eq(Addressable::URI.parse(expected_uri)) + expect(hostname).to eq(expected_hostname) + end + end + context 'when URI is nil' do let(:import_url) { nil } - it 'returns no URI and hostname' do - uri, hostname = described_class.validate!(import_url) - - expect(uri).to be(nil) - expect(hostname).to be(nil) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { nil } + let(:expected_hostname) { nil } end end context 'when URI is internal' do let(:import_url) { 'http://localhost' } - it 'returns URI and no hostname' do - uri, hostname = described_class.validate!(import_url) - - expect(uri).to eq(Addressable::URI.parse('http://[::1]')) - expect(hostname).to eq('localhost') + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { 'http://[::1]' } + let(:expected_hostname) { 'localhost' } end end context 'when the URL hostname is a domain' do - let(:import_url) { 'https://example.org' } + context 'when domain can be resolved' do + let(:import_url) { 'https://example.org' } - it 'returns URI and hostname' do - uri, hostname = described_class.validate!(import_url) + before do + stub_dns(import_url, ip_address: '93.184.216.34') + end - expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) - expect(hostname).to eq('example.org') + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { 'https://93.184.216.34' } + let(:expected_hostname) { 'example.org' } + end + end + + context 'when domain cannot be resolved' do + let(:import_url) { 'http://foobar.x' } + + it 'raises an error' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect { subject }.to raise_error(described_class::BlockedUrlError) + end end end context 'when the URL hostname is an IP address' do let(:import_url) { 'https://93.184.216.34' } - it 'returns URI and no hostname' do - uri, hostname = described_class.validate!(import_url) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } + end + + context 'when the address is invalid' do + let(:import_url) { 'http://1.1.1.1.1' } - expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) - expect(hostname).to be(nil) + it 'raises an error' do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + + expect { subject }.to raise_error(described_class::BlockedUrlError) + end end end context 'disabled DNS rebinding protection' do + subject { described_class.validate!(import_url, dns_rebind_protection: false) } + context 'when URI is internal' do let(:import_url) { 'http://localhost' } - it 'returns URI and no hostname' do - uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) - - expect(uri).to eq(Addressable::URI.parse('http://localhost')) - expect(hostname).to be(nil) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } end end context 'when the URL hostname is a domain' do let(:import_url) { 'https://example.org' } - it 'returns URI and no hostname' do - uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) + before do + stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') + end - expect(uri).to eq(Addressable::URI.parse('https://example.org')) - expect(hostname).to eq(nil) + context 'when domain can be resolved' do + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } + end end - context 'when it cannot be resolved' do + context 'when domain cannot be resolved' do let(:import_url) { 'http://foobar.x' } - it 'raises error' do - stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') - - expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } end end end @@ -85,20 +119,17 @@ describe Gitlab::UrlBlocker do context 'when the URL hostname is an IP address' do let(:import_url) { 'https://93.184.216.34' } - it 'returns URI and no hostname' do - uri, hostname = described_class.validate!(import_url, dns_rebind_protection: false) - - expect(uri).to eq(Addressable::URI.parse('https://93.184.216.34')) - expect(hostname).to be(nil) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } end context 'when it is invalid' do let(:import_url) { 'http://1.1.1.1.1' } - it 'raises an error' do - stub_env('RSPEC_ALLOW_INVALID_URLS', 'false') - - expect { described_class.validate!(import_url) }.to raise_error(described_class::BlockedUrlError) + it_behaves_like 'validates URI and hostname' do + let(:expected_uri) { import_url } + let(:expected_hostname) { nil } end end end diff --git a/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb new file mode 100644 index 00000000000..4be4a661260 --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/merge_request_counter_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UsageDataCounters::MergeRequestCounter do + it_behaves_like 'a redis usage counter', 'Merge Request', :create + + it_behaves_like 'a redis usage counter with totals', :merge_request, create: 5 +end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index dda119e09b1..b3a179e276b 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -69,6 +69,7 @@ describe Gitlab::UsageData do snippet_update: a_kind_of(Integer), snippet_comment: a_kind_of(Integer), merge_request_comment: a_kind_of(Integer), + merge_request_create: a_kind_of(Integer), commit_comment: a_kind_of(Integer), wiki_pages_create: a_kind_of(Integer), wiki_pages_update: a_kind_of(Integer), diff --git a/spec/lib/gitlab/visibility_level_checker_spec.rb b/spec/lib/gitlab/visibility_level_checker_spec.rb new file mode 100644 index 00000000000..325ac3c6f31 --- /dev/null +++ b/spec/lib/gitlab/visibility_level_checker_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe Gitlab::VisibilityLevelChecker do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:visibility_level_checker) { } + let(:override_params) { {} } + + subject { described_class.new(user, project, project_params: override_params) } + + describe '#level_restricted?' do + context 'when visibility level is allowed' do + it 'returns false with nil for visibility level' do + result = subject.level_restricted? + + expect(result.restricted?).to eq(false) + expect(result.visibility_level).to be_nil + end + end + + context 'when visibility level is restricted' do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it 'returns true and visibility name' do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + result = subject.level_restricted? + + expect(result.restricted?).to eq(true) + expect(result.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + + context 'overridden visibility' do + let(:override_params) do + { + import_data: { + data: { + override_params: { + visibility: override_visibility + } + } + } + } + end + + context 'when restricted' do + let(:override_visibility) { 'public' } + + it 'returns true and visibility name' do + result = subject.level_restricted? + + expect(result.restricted?).to eq(true) + expect(result.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + end + + context 'when misspelled' do + let(:override_visibility) { 'publik' } + + it 'returns false with nil for visibility level' do + result = subject.level_restricted? + + expect(result.restricted?).to eq(false) + expect(result.visibility_level).to be_nil + end + end + + context 'when import_data is missing' do + let(:override_params) { {} } + + it 'returns false with nil for visibility level' do + result = subject.level_restricted? + + expect(result.restricted?).to eq(false) + expect(result.visibility_level).to be_nil + end + end + end + end + end +end diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 5c5ff46112f..88bc5034da5 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -14,6 +14,12 @@ describe Gitlab::Workhorse do [key, command, params] end + before do + allow(Feature::Gitaly).to receive(:server_feature_flags).and_return({ + 'gitaly-feature-foobar' => 'true' + }) + end + describe ".send_git_archive" do let(:ref) { 'master' } let(:format) { 'zip' } @@ -41,6 +47,7 @@ describe Gitlab::Workhorse do expected_params = metadata.merge( 'GitalyRepository' => repository.gitaly_repository.to_h, 'GitalyServer' => { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) } @@ -69,6 +76,7 @@ describe Gitlab::Workhorse do expect(command).to eq('git-archive') expect(params).to eq({ 'GitalyServer' => { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -117,6 +125,7 @@ describe Gitlab::Workhorse do expect(command).to eq("git-format-patch") expect(params).to eq({ 'GitalyServer' => { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -178,6 +187,7 @@ describe Gitlab::Workhorse do expect(command).to eq("git-diff") expect(params).to eq({ 'GitalyServer' => { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -190,57 +200,6 @@ describe Gitlab::Workhorse do end end - describe ".secret" do - subject { described_class.secret } - - before do - described_class.instance_variable_set(:@secret, nil) - described_class.write_secret - end - - it 'returns 32 bytes' do - expect(subject).to be_a(String) - expect(subject.length).to eq(32) - expect(subject.encoding).to eq(Encoding::ASCII_8BIT) - end - - it 'accepts a trailing newline' do - File.open(described_class.secret_path, 'a') { |f| f.write "\n" } - expect(subject.length).to eq(32) - end - - it 'raises an exception if the secret file cannot be read' do - File.delete(described_class.secret_path) - expect { subject }.to raise_exception(Errno::ENOENT) - end - - it 'raises an exception if the secret file contains the wrong number of bytes' do - File.truncate(described_class.secret_path, 0) - expect { subject }.to raise_exception(RuntimeError) - end - end - - describe ".write_secret" do - let(:secret_path) { described_class.secret_path } - before do - begin - File.delete(secret_path) - rescue Errno::ENOENT - end - - described_class.write_secret - end - - it 'uses mode 0600' do - expect(File.stat(secret_path).mode & 0777).to eq(0600) - end - - it 'writes base64 data' do - bytes = Base64.strict_decode64(File.read(secret_path)) - expect(bytes).not_to be_empty - end - end - describe '#verify_api_request!' do let(:header_key) { described_class::INTERNAL_API_REQUEST_HEADER } let(:payload) { { 'iss' => 'gitlab-workhorse' } } @@ -315,6 +274,7 @@ describe Gitlab::Workhorse do let(:gitaly_params) do { GitalyServer: { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address('default'), token: Gitlab::GitalyClient.token('default') } @@ -463,6 +423,7 @@ describe Gitlab::Workhorse do expect(command).to eq('git-blob') expect(params).to eq({ 'GitalyServer' => { + features: { 'gitaly-feature-foobar' => 'true' }, address: Gitlab::GitalyClient.address(project.repository_storage), token: Gitlab::GitalyClient.token(project.repository_storage) }, @@ -504,6 +465,7 @@ describe Gitlab::Workhorse do expect(command).to eq('git-snapshot') expect(params).to eq( 'GitalyServer' => { + 'features' => { 'gitaly-feature-foobar' => 'true' }, 'address' => Gitlab::GitalyClient.address(project.repository_storage), 'token' => Gitlab::GitalyClient.token(project.repository_storage) }, |