diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 09:45:46 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 09:45:46 +0000 |
commit | a7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch) | |
tree | 7452bd5c3545c2fa67a28aa013835fb4fa071baf /spec/models/concerns | |
parent | ee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff) | |
download | gitlab-ce-a7b3560714b4d9cc4ab32dffcd1f74a284b93580.tar.gz |
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'spec/models/concerns')
-rw-r--r-- | spec/models/concerns/after_commit_queue_spec.rb | 4 | ||||
-rw-r--r-- | spec/models/concerns/ci/has_variable_spec.rb | 39 | ||||
-rw-r--r-- | spec/models/concerns/cross_database_modification_spec.rb | 89 | ||||
-rw-r--r-- | spec/models/concerns/has_environment_scope_spec.rb | 32 | ||||
-rw-r--r-- | spec/models/concerns/issuable_spec.rb | 8 | ||||
-rw-r--r-- | spec/models/concerns/resolvable_discussion_spec.rb | 10 | ||||
-rw-r--r-- | spec/models/concerns/taskable_spec.rb | 66 | ||||
-rw-r--r-- | spec/models/concerns/token_authenticatable_spec.rb | 138 | ||||
-rw-r--r-- | spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb | 10 |
9 files changed, 392 insertions, 4 deletions
diff --git a/spec/models/concerns/after_commit_queue_spec.rb b/spec/models/concerns/after_commit_queue_spec.rb index 40cddde333e..8f091081dce 100644 --- a/spec/models/concerns/after_commit_queue_spec.rb +++ b/spec/models/concerns/after_commit_queue_spec.rb @@ -75,7 +75,7 @@ RSpec.describe AfterCommitQueue do skip_if_multiple_databases_not_setup table_sql = <<~SQL - CREATE TABLE _test_ci_after_commit_queue ( + CREATE TABLE _test_gitlab_ci_after_commit_queue ( id serial NOT NULL PRIMARY KEY); SQL @@ -84,7 +84,7 @@ RSpec.describe AfterCommitQueue do let(:ci_klass) do Class.new(Ci::ApplicationRecord) do - self.table_name = '_test_ci_after_commit_queue' + self.table_name = '_test_gitlab_ci_after_commit_queue' include AfterCommitQueue diff --git a/spec/models/concerns/ci/has_variable_spec.rb b/spec/models/concerns/ci/has_variable_spec.rb index e917ec6b802..bf699119a37 100644 --- a/spec/models/concerns/ci/has_variable_spec.rb +++ b/spec/models/concerns/ci/has_variable_spec.rb @@ -68,9 +68,48 @@ RSpec.describe Ci::HasVariable do end describe '#to_runner_variable' do + let_it_be(:ci_variable) { create(:ci_variable) } + + subject { ci_variable } + it 'returns a hash for the runner' do expect(subject.to_runner_variable) .to include(key: subject.key, value: subject.value, public: false) end + + context 'with RequestStore enabled', :request_store do + let(:expected) do + { + file: false, + key: subject.key, + value: subject.value, + public: false, + masked: false + } + end + + it 'decrypts once' do + expect(OpenSSL::PKCS5).to receive(:pbkdf2_hmac).once.and_call_original + + 2.times { expect(subject.reload.to_runner_variable).to eq(expected) } + end + + it 'does not cache similar keys', :aggregate_failures do + group_var = create(:ci_group_variable, key: subject.key, value: 'group') + project_var = create(:ci_variable, key: subject.key, value: 'project') + + expect(subject.to_runner_variable).to include(key: subject.key, value: subject.value) + expect(group_var.to_runner_variable).to include(key: subject.key, value: 'group') + expect(project_var.to_runner_variable).to include(key: subject.key, value: 'project') + end + + it 'does not cache unpersisted values' do + new_variable = Ci::Variable.new(key: SecureRandom.hex, value: "12345") + old_value = new_variable.to_runner_variable + new_variable.value = '98765' + + expect(new_variable.to_runner_variable).not_to eq(old_value) + end + end end end diff --git a/spec/models/concerns/cross_database_modification_spec.rb b/spec/models/concerns/cross_database_modification_spec.rb new file mode 100644 index 00000000000..72544536953 --- /dev/null +++ b/spec/models/concerns/cross_database_modification_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe CrossDatabaseModification do + describe '.transaction' do + context 'feature flag disabled' do + before do + stub_feature_flags(track_gitlab_schema_in_current_transaction: false) + end + + it 'does not add to gitlab_transactions_stack' do + ApplicationRecord.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + end + end + + context 'feature flag is not yet setup' do + before do + allow(Feature::FlipperFeature).to receive(:table_exists?).and_raise(ActiveRecord::NoDatabaseError) + end + + it 'does not add to gitlab_transactions_stack' do + ApplicationRecord.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + end + end + + it 'adds the current gitlab schema to gitlab_transactions_stack', :aggregate_failures do + ApplicationRecord.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main) + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + Ci::ApplicationRecord.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_ci) + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + Project.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main) + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + Ci::Pipeline.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_ci) + + Project.first + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + + ApplicationRecord.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main) + + Ci::Pipeline.transaction do + expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main, :gitlab_ci) + + Project.first + end + end + + expect(ApplicationRecord.gitlab_transactions_stack).to be_empty + end + + it 'yields' do + expect { |block| ApplicationRecord.transaction(&block) }.to yield_control + end + end +end diff --git a/spec/models/concerns/has_environment_scope_spec.rb b/spec/models/concerns/has_environment_scope_spec.rb index 0cc997709c9..6e8394b6fa5 100644 --- a/spec/models/concerns/has_environment_scope_spec.rb +++ b/spec/models/concerns/has_environment_scope_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe HasEnvironmentScope do + let_it_be(:project) { create(:project) } + subject { build(:ci_variable) } it { is_expected.to allow_value('*').for(:environment_scope) } @@ -17,8 +19,6 @@ RSpec.describe HasEnvironmentScope do end describe '.on_environment' do - let(:project) { create(:project) } - it 'returns scoped objects' do variable1 = create(:ci_variable, project: project, environment_scope: '*') variable2 = create(:ci_variable, project: project, environment_scope: 'product/*') @@ -63,4 +63,32 @@ RSpec.describe HasEnvironmentScope do end end end + + describe '.for_environment' do + subject { project.variables.for_environment(environment) } + + let_it_be(:variable1) do + create(:ci_variable, project: project, environment_scope: '*') + end + + let_it_be(:variable2) do + create(:ci_variable, project: project, environment_scope: 'production/*') + end + + let_it_be(:variable3) do + create(:ci_variable, project: project, environment_scope: 'staging/*') + end + + context 'when the environment is present' do + let(:environment) { 'production/canary-1' } + + it { is_expected.to eq([variable1, variable2]) } + end + + context 'when the environment is nil' do + let(:environment) {} + + it { is_expected.to eq([variable1]) } + end + end end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index e9c3d1dc646..832d5b44e5d 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -935,6 +935,14 @@ RSpec.describe Issuable do subject { issuable.supports_escalation? } it { is_expected.to eq(supports_escalation) } + + context 'with feature disabled' do + before do + stub_feature_flags(incident_escalations: false) + end + + it { is_expected.to eq(false) } + end end end diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index fc154738f11..7e08f47fb5a 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -584,4 +584,14 @@ RSpec.describe Discussion, ResolvableDiscussion do expect(subject.last_resolved_note).to eq(second_note) end end + + describe '#clear_memoized_values' do + it 'resets the memoized values' do + described_class.memoized_values.each do |memo| + subject.instance_variable_set("@#{memo}", 'memoized') + expect { subject.clear_memoized_values }.to change { subject.instance_variable_get("@#{memo}") } + .from('memoized').to(nil) + end + end + end end diff --git a/spec/models/concerns/taskable_spec.rb b/spec/models/concerns/taskable_spec.rb new file mode 100644 index 00000000000..6b41174a046 --- /dev/null +++ b/spec/models/concerns/taskable_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Taskable do + using RSpec::Parameterized::TableSyntax + + describe '.get_tasks' do + let(:description) do + <<~MARKDOWN + Any text before the list + - [ ] First item + - [x] Second item + * [x] First item + * [ ] Second item + MARKDOWN + end + + let(:expected_result) do + [ + TaskList::Item.new('- [ ]', 'First item'), + TaskList::Item.new('- [x]', 'Second item'), + TaskList::Item.new('* [x]', 'First item'), + TaskList::Item.new('* [ ]', 'Second item') + ] + end + + subject { described_class.get_tasks(description) } + + it { is_expected.to match(expected_result) } + end + + describe '#task_list_items' do + where(issuable_type: [:issue, :merge_request]) + + with_them do + let(:issuable) { build(issuable_type, description: description) } + + subject(:result) { issuable.task_list_items } + + context 'when description is present' do + let(:description) { 'markdown' } + + it 'gets tasks from markdown' do + expect(described_class).to receive(:get_tasks) + + result + end + end + + context 'when description is blank' do + let(:description) { '' } + + it 'returns empty array' do + expect(result).to be_empty + end + + it 'does not try to get tasks from markdown' do + expect(described_class).not_to receive(:get_tasks) + + result + end + end + end + end +end diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 4bdb3e0a32a..2e82a12a61a 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -289,4 +289,142 @@ RSpec.describe Ci::Build, 'TokenAuthenticatable' do expect(build.read_attribute('token')).to be_nil end end + + describe '#token_with_expiration' do + describe '#expirable?' do + subject { build.token_with_expiration.expirable? } + + it { is_expected.to eq(false) } + end + end +end + +RSpec.describe Ci::Runner, 'TokenAuthenticatable', :freeze_time do + let_it_be(:non_expirable_runner) { create(:ci_runner) } + let_it_be(:non_expired_runner) { create(:ci_runner).tap { |r| r.update!(token_expires_at: 5.seconds.from_now) } } + let_it_be(:expired_runner) { create(:ci_runner).tap { |r| r.update!(token_expires_at: 5.seconds.ago) } } + + describe '#token_expired?' do + subject { runner.token_expired? } + + context 'when enforce_runner_token_expires_at feature flag is disabled' do + before do + stub_feature_flags(enforce_runner_token_expires_at: false) + end + + context 'when runner has no token expiration' do + let(:runner) { non_expirable_runner } + + it { is_expected.to eq(false) } + end + + context 'when runner token is not expired' do + let(:runner) { non_expired_runner } + + it { is_expected.to eq(false) } + end + + context 'when runner token is expired' do + let(:runner) { expired_runner } + + it { is_expected.to eq(false) } + end + end + + context 'when enforce_runner_token_expires_at feature flag is enabled' do + before do + stub_feature_flags(enforce_runner_token_expires_at: true) + end + + context 'when runner has no token expiration' do + let(:runner) { non_expirable_runner } + + it { is_expected.to eq(false) } + end + + context 'when runner token is not expired' do + let(:runner) { non_expired_runner } + + it { is_expected.to eq(false) } + end + + context 'when runner token is expired' do + let(:runner) { expired_runner } + + it { is_expected.to eq(true) } + end + end + end + + describe '#token_with_expiration' do + describe '#token' do + subject { non_expired_runner.token_with_expiration.token } + + it { is_expected.to eq(non_expired_runner.token) } + end + + describe '#token_expires_at' do + subject { non_expired_runner.token_with_expiration.token_expires_at } + + it { is_expected.to eq(non_expired_runner.token_expires_at) } + end + + describe '#expirable?' do + subject { non_expired_runner.token_with_expiration.expirable? } + + it { is_expected.to eq(true) } + end + end + + describe '.find_by_token' do + subject { Ci::Runner.find_by_token(runner.token) } + + context 'when enforce_runner_token_expires_at feature flag is disabled' do + before do + stub_feature_flags(enforce_runner_token_expires_at: false) + end + + context 'when runner has no token expiration' do + let(:runner) { non_expirable_runner } + + it { is_expected.to eq(non_expirable_runner) } + end + + context 'when runner token is not expired' do + let(:runner) { non_expired_runner } + + it { is_expected.to eq(non_expired_runner) } + end + + context 'when runner token is expired' do + let(:runner) { expired_runner } + + it { is_expected.to eq(expired_runner) } + end + end + + context 'when enforce_runner_token_expires_at feature flag is enabled' do + before do + stub_feature_flags(enforce_runner_token_expires_at: true) + end + + context 'when runner has no token expiration' do + let(:runner) { non_expirable_runner } + + it { is_expected.to eq(non_expirable_runner) } + end + + context 'when runner token is not expired' do + let(:runner) { non_expired_runner } + + it { is_expected.to eq(non_expired_runner) } + end + + context 'when runner token is expired' do + let(:runner) { expired_runner } + + it { is_expected.to be_nil } + end + end + end end diff --git a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb index b311e302a31..1772fd0ff95 100644 --- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb +++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb @@ -23,6 +23,8 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do let(:options) { { encrypted: :required } } it 'finds the encrypted resource by cleartext' do + allow(model).to receive(:where) + .and_return(model) allow(model).to receive(:find_by) .with('some_field_encrypted' => [encrypted, encrypted_with_static_iv]) .and_return('encrypted resource') @@ -36,6 +38,8 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do let(:options) { { encrypted: :optional } } it 'finds the encrypted resource by cleartext' do + allow(model).to receive(:where) + .and_return(model) allow(model).to receive(:find_by) .with('some_field_encrypted' => [encrypted, encrypted_with_static_iv]) .and_return('encrypted resource') @@ -49,6 +53,8 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do .to receive(:find_token_authenticatable) .and_return('plaintext resource') + allow(model).to receive(:where) + .and_return(model) allow(model).to receive(:find_by) .with('some_field_encrypted' => [encrypted, encrypted_with_static_iv]) .and_return(nil) @@ -62,6 +68,8 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do let(:options) { { encrypted: :migrating } } it 'finds the cleartext resource by cleartext' do + allow(model).to receive(:where) + .and_return(model) allow(model).to receive(:find_by) .with('some_field' => 'my-value') .and_return('cleartext resource') @@ -71,6 +79,8 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do end it 'returns nil if resource cannot be found' do + allow(model).to receive(:where) + .and_return(model) allow(model).to receive(:find_by) .with('some_field' => 'my-value') .and_return(nil) |