diff options
Diffstat (limited to 'spec/models/concerns')
16 files changed, 546 insertions, 55 deletions
diff --git a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb index 993afd47a57..358000ee174 100644 --- a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb +++ b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb @@ -6,10 +6,10 @@ RSpec.describe BatchDestroyDependentAssociations do class TestProject < ActiveRecord::Base self.table_name = 'projects' - has_many :builds, dependent: :destroy + has_many :builds has_many :notification_settings, as: :source, dependent: :delete_all has_many :pages_domains - has_many :todos + has_many :todos, dependent: :destroy include BatchDestroyDependentAssociations end @@ -18,7 +18,7 @@ RSpec.describe BatchDestroyDependentAssociations do let_it_be(:project) { TestProject.new } it 'returns the right associations' do - expect(project.dependent_associations_to_destroy.map(&:name)).to match_array([:builds]) + expect(project.dependent_associations_to_destroy.map(&:name)).to match_array([:todos]) end end @@ -26,36 +26,35 @@ RSpec.describe BatchDestroyDependentAssociations do let_it_be(:project) { create(:project) } let_it_be(:build) { create(:ci_build, project: project) } let_it_be(:notification_setting) { create(:notification_setting, project: project) } + let_it_be(:note) { create(:note, project: project) } - let!(:todos) { create(:todo, project: project) } + it 'destroys multiple notes' do + create(:note, project: project) - it 'destroys multiple builds' do - create(:ci_build, project: project) - - expect(Ci::Build.count).to eq(2) + expect(Note.count).to eq(2) project.destroy_dependent_associations_in_batches - expect(Ci::Build.count).to eq(0) + expect(Note.count).to eq(0) end - it 'destroys builds in batches' do - expect(project).to receive_message_chain(:builds, :find_each).and_yield(build) - expect(build).to receive(:destroy).and_call_original + it 'destroys note in batches' do + expect(project).to receive_message_chain(:notes, :find_each).and_yield(note) + expect(note).to receive(:destroy).and_call_original project.destroy_dependent_associations_in_batches - expect(Ci::Build.count).to eq(0) - expect(Todo.count).to eq(1) + expect(Ci::Build.count).to eq(1) + expect(Note.count).to eq(0) expect(User.count).to be > 0 expect(NotificationSetting.count).to eq(User.count) end it 'excludes associations' do - project.destroy_dependent_associations_in_batches(exclude: [:builds]) + project.destroy_dependent_associations_in_batches(exclude: [:notes]) + expect(Note.count).to eq(1) expect(Ci::Build.count).to eq(1) - expect(Todo.count).to eq(1) expect(User.count).to be > 0 expect(NotificationSetting.count).to eq(User.count) end diff --git a/spec/models/concerns/blocks_json_serialization_spec.rb b/spec/models/concerns/blocks_json_serialization_spec.rb deleted file mode 100644 index d811b47fa35..00000000000 --- a/spec/models/concerns/blocks_json_serialization_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe BlocksJsonSerialization do - before do - stub_const('DummyModel', Class.new) - DummyModel.class_eval do - include BlocksJsonSerialization - end - end - - it 'blocks as_json' do - expect { DummyModel.new.as_json } - .to raise_error(described_class::JsonSerializationError, /DummyModel/) - end - - it 'blocks to_json' do - expect { DummyModel.new.to_json } - .to raise_error(described_class::JsonSerializationError, /DummyModel/) - end -end diff --git a/spec/models/concerns/blocks_unsafe_serialization_spec.rb b/spec/models/concerns/blocks_unsafe_serialization_spec.rb new file mode 100644 index 00000000000..5c8f5035a58 --- /dev/null +++ b/spec/models/concerns/blocks_unsafe_serialization_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe BlocksUnsafeSerialization do + before do + stub_const('DummyModel', Class.new) + DummyModel.class_eval do + include ActiveModel::Serializers::JSON + include BlocksUnsafeSerialization + end + end + + it_behaves_like 'blocks unsafe serialization' do + let(:object) { DummyModel.new } + end +end diff --git a/spec/models/concerns/ci/has_deployment_name_spec.rb b/spec/models/concerns/ci/has_deployment_name_spec.rb new file mode 100644 index 00000000000..8c7338638b1 --- /dev/null +++ b/spec/models/concerns/ci/has_deployment_name_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::HasDeploymentName do + describe 'deployment_name?' do + let(:build) { create(:ci_build) } + + subject { build.branch? } + + it 'does detect deployment names' do + build.name = 'deployment' + + expect(build.deployment_name?).to be_truthy + end + + it 'does detect partial deployment names' do + build.name = 'do a really cool deploy' + + expect(build.deployment_name?).to be_truthy + end + + it 'does not detect non-deployment names' do + build.name = 'testing' + + expect(build.deployment_name?).to be_falsy + end + + it 'is case insensitive' do + build.name = 'DEPLOY' + expect(build.deployment_name?).to be_truthy + end + end +end diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb index 7fa55184cf1..bd1afe844ac 100644 --- a/spec/models/concerns/deployment_platform_spec.rb +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -12,16 +12,28 @@ RSpec.describe DeploymentPlatform do let(:group) { create(:group) } let(:project) { create(:project, group: group) } + shared_examples 'certificate_based_clusters is disabled' do + before do + stub_feature_flags(certificate_based_clusters: false) + end + + it { is_expected.to be_nil } + end + shared_examples 'matching environment scope' do it 'returns environment specific cluster' do is_expected.to eq(cluster.platform_kubernetes) end + + it_behaves_like 'certificate_based_clusters is disabled' end shared_examples 'not matching environment scope' do it 'returns default cluster' do is_expected.to eq(default_cluster.platform_kubernetes) end + + it_behaves_like 'certificate_based_clusters is disabled' end context 'multiple clusters use the same management project' do diff --git a/spec/models/concerns/issuable_link_spec.rb b/spec/models/concerns/issuable_link_spec.rb new file mode 100644 index 00000000000..7be6d8a074d --- /dev/null +++ b/spec/models/concerns/issuable_link_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IssuableLink do + let(:test_class) do + Class.new(ApplicationRecord) do + include IssuableLink + + self.table_name = 'issue_links' + + belongs_to :source, class_name: 'Issue' + belongs_to :target, class_name: 'Issue' + + def self.name + 'TestClass' + end + end + end + + describe '.inverse_link_type' do + it 'returns the inverse type of link' do + expect(test_class.inverse_link_type('relates_to')).to eq('relates_to') + end + end + + describe '.issuable_type' do + let_it_be(:source_issue) { create(:issue) } + let_it_be(:target_issue) { create(:issue) } + + before do + test_class.create!(source: source_issue, target: target_issue) + end + + context 'when opposite relation already exists' do + it 'raises NotImplementedError when performing validations' do + instance = test_class.new(source: target_issue, target: source_issue) + + expect { instance.save! }.to raise_error(NotImplementedError) + end + end + end +end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 832d5b44e5d..e3c0e3a7a2b 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -18,7 +18,6 @@ RSpec.describe Issuable do it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:todos) } it { is_expected.to have_many(:labels) } - it { is_expected.to have_many(:note_authors).through(:notes) } context 'Notes' do let!(:note) { create(:note, noteable: issue, project: issue.project) } @@ -28,6 +27,23 @@ RSpec.describe Issuable do expect(issue.notes).not_to be_authors_loaded expect(scoped_issue.notes).to be_authors_loaded end + + describe 'note_authors' do + it { is_expected.to have_many(:note_authors).through(:notes) } + end + + describe 'user_note_authors' do + let_it_be(:system_user) { create(:user) } + + let!(:system_note) { create(:system_note, author: system_user, noteable: issue, project: issue.project) } + + it 'filters the authors to those of user notes' do + authors = issue.user_note_authors + + expect(authors).to include(note.author) + expect(authors).not_to include(system_user) + end + end end end @@ -572,6 +588,27 @@ RSpec.describe Issuable do issue.to_hook_data(user, old_associations: { severity: 'unknown' }) end end + + context 'escalation status is updated' do + let(:issue) { create(:incident, :with_escalation_status) } + let(:acknowledged) { IncidentManagement::IssuableEscalationStatus::STATUSES[:acknowledged] } + + before do + issue.escalation_status.update!(status: acknowledged) + + expect(Gitlab::HookData::IssuableBuilder).to receive(:new).with(issue).and_return(builder) + end + + it 'delegates to Gitlab::HookData::IssuableBuilder#build' do + expect(builder).to receive(:build).with( + user: user, + changes: hash_including( + 'escalation_status' => %i(triggered acknowledged) + )) + + issue.to_hook_data(user, old_associations: { escalation_status: :triggered }) + end + end end describe '#labels_array' do @@ -761,7 +798,7 @@ RSpec.describe Issuable do it 'updates issues updated_at' do issue - Timecop.travel(1.minute.from_now) do + travel_to(2.minutes.from_now) do expect { spend_time(1800) }.to change { issue.updated_at } end end @@ -786,7 +823,7 @@ RSpec.describe Issuable do context 'when time to subtract exceeds the total time spent' do it 'raise a validation error' do - Timecop.travel(1.minute.from_now) do + travel_to(1.minute.from_now) do expect do expect do spend_time(-3600) diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index 3c095477ea9..9daea3438cb 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -9,6 +9,7 @@ RSpec.describe Mentionable do include Mentionable attr_accessor :project, :message + attr_mentionable :message def author diff --git a/spec/models/concerns/pg_full_text_searchable_spec.rb b/spec/models/concerns/pg_full_text_searchable_spec.rb new file mode 100644 index 00000000000..db7f652f494 --- /dev/null +++ b/spec/models/concerns/pg_full_text_searchable_spec.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PgFullTextSearchable do + let(:project) { create(:project) } + + let(:model_class) do + Class.new(ActiveRecord::Base) do + include PgFullTextSearchable + + self.table_name = 'issues' + + belongs_to :project + has_one :search_data, class_name: 'Issues::SearchData' + + def persist_pg_full_text_search_vector(search_vector) + Issues::SearchData.upsert({ project_id: project_id, issue_id: id, search_vector: search_vector }, unique_by: %i(project_id issue_id)) + end + + def self.name + 'Issue' + end + end + end + + describe '.pg_full_text_searchable' do + it 'sets pg_full_text_searchable_columns' do + model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }] + + expect(model_class.pg_full_text_searchable_columns).to eq({ 'title' => 'A' }) + end + + it 'raises an error when called twice' do + model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }] + + expect { model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }] }.to raise_error('Full text search columns already defined!') + end + end + + describe 'after commit hook' do + let(:model) { model_class.create!(project: project) } + + before do + model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }] + end + + context 'when specified columns are changed' do + it 'calls update_search_data!' do + expect(model).to receive(:update_search_data!) + + model.update!(title: 'A new title') + end + end + + context 'when specified columns are not changed' do + it 'does not enqueue worker' do + expect(model).not_to receive(:update_search_data!) + + model.update!(description: 'A new description') + end + end + end + + describe '.pg_full_text_search' do + let(:english) { model_class.create!(project: project, title: 'title', description: 'something english') } + let(:with_accent) { model_class.create!(project: project, title: 'Jürgen', description: 'Ærøskøbing') } + let(:japanese) { model_class.create!(project: project, title: '日本語 title', description: 'another english description') } + + before do + model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }] + + [english, with_accent, japanese].each(&:update_search_data!) + end + + it 'searches across all fields' do + expect(model_class.pg_full_text_search('title english')).to contain_exactly(english, japanese) + end + + it 'searches for exact term with quotes' do + expect(model_class.pg_full_text_search('"something english"')).to contain_exactly(english) + end + + it 'ignores accents' do + expect(model_class.pg_full_text_search('jurgen')).to contain_exactly(with_accent) + end + + it 'does not support searching by non-Latin characters' do + expect(model_class.pg_full_text_search('日本')).to be_empty + end + end + + describe '#update_search_data!' do + let(:model) { model_class.create!(project: project, title: 'title', description: 'description') } + + before do + model_class.pg_full_text_searchable columns: [{ name: 'title', weight: 'A' }, { name: 'description', weight: 'B' }] + end + + it 'sets the correct weights' do + model.update_search_data! + + expect(model.search_data.search_vector).to match(/'titl':1A/) + expect(model.search_data.search_vector).to match(/'descript':2B/) + end + + context 'with accented and non-Latin characters' do + let(:model) { model_class.create!(project: project, title: '日本語', description: 'Jürgen') } + + it 'transliterates accented characters and removes non-Latin ones' do + model.update_search_data! + + expect(model.search_data.search_vector).not_to match(/日本語/) + expect(model.search_data.search_vector).to match(/jurgen/) + end + end + + context 'with long words' do + let(:model) { model_class.create!(project: project, title: 'title ' + 'long/sequence+1' * 4, description: 'description ' + '@user1' * 20) } + + it 'strips words that are 50 characters or longer' do + model.update_search_data! + + expect(model.search_data.search_vector).to match(/'titl':1A/) + expect(model.search_data.search_vector).not_to match(/long/) + expect(model.search_data.search_vector).not_to match(/sequence/) + + expect(model.search_data.search_vector).to match(/'descript':2B/) + expect(model.search_data.search_vector).not_to match(/@user1/) + end + end + + context 'when upsert times out' do + it 're-raises the exception' do + expect(Issues::SearchData).to receive(:upsert).once.and_raise(ActiveRecord::StatementTimeout) + + expect { model.update_search_data! }.to raise_error(ActiveRecord::StatementTimeout) + end + end + + context 'with strings that go over tsvector limit', :delete do + let(:long_string) { Array.new(30_000) { SecureRandom.hex }.join(' ') } + let(:model) { model_class.create!(project: project, title: 'title', description: long_string) } + + it 'does not raise an exception' do + expect(Gitlab::AppJsonLogger).to receive(:error).with( + a_hash_including(class: model_class.name, model_id: model.id) + ) + + expect { model.update_search_data! }.not_to raise_error + + expect(model.search_data).to eq(nil) + end + end + + context 'when model class does not implement persist_pg_full_text_search_vector' do + let(:model_class) do + Class.new(ActiveRecord::Base) do + include PgFullTextSearchable + + self.table_name = 'issues' + + belongs_to :project + has_one :search_data, class_name: 'Issues::SearchData' + + def self.name + 'Issue' + end + end + end + + it 'raises an error' do + expect { model.update_search_data! }.to raise_error(NotImplementedError) + end + end + end +end diff --git a/spec/models/concerns/runners_token_prefixable_spec.rb b/spec/models/concerns/runners_token_prefixable_spec.rb index 6127203987f..29e7b8cf4f4 100644 --- a/spec/models/concerns/runners_token_prefixable_spec.rb +++ b/spec/models/concerns/runners_token_prefixable_spec.rb @@ -3,18 +3,11 @@ require 'spec_helper' RSpec.describe RunnersTokenPrefixable do - before do - stub_const('DummyModel', Class.new) - DummyModel.class_eval do - include RunnersTokenPrefixable - end - end - - describe '.runners_token_prefix' do - subject { DummyModel.new } + describe 'runners token prefix' do + subject { described_class::RUNNERS_TOKEN_PREFIX } - it 'returns RUNNERS_TOKEN_PREFIX' do - expect(subject.runners_token_prefix).to eq(RunnersTokenPrefixable::RUNNERS_TOKEN_PREFIX) + it 'has the correct value' do + expect(subject).to eq('GR1348941') end end end diff --git a/spec/models/concerns/sensitive_serializable_hash_spec.rb b/spec/models/concerns/sensitive_serializable_hash_spec.rb new file mode 100644 index 00000000000..923f9e80c1f --- /dev/null +++ b/spec/models/concerns/sensitive_serializable_hash_spec.rb @@ -0,0 +1,150 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe SensitiveSerializableHash do + describe '.prevent_from_serialization' do + let(:test_class) do + Class.new do + include ActiveModel::Serialization + include SensitiveSerializableHash + + attr_accessor :name, :super_secret + + prevent_from_serialization :super_secret + + def attributes + { 'name' => nil, 'super_secret' => nil } + end + end + end + + let(:model) { test_class.new } + + it 'does not include the field in serializable_hash' do + expect(model.serializable_hash).not_to include('super_secret') + end + + context 'unsafe_serialization_hash option' do + it 'includes the field in serializable_hash' do + expect(model.serializable_hash(unsafe_serialization_hash: true)).to include('super_secret') + end + end + + context 'when prevent_sensitive_fields_from_serializable_hash feature flag is disabled' do + before do + stub_feature_flags(prevent_sensitive_fields_from_serializable_hash: false) + end + + it 'includes the field in serializable_hash' do + expect(model.serializable_hash).to include('super_secret') + end + end + end + + describe '#serializable_hash' do + shared_examples "attr_encrypted attribute" do |klass, attribute_name| + context "#{klass.name}\##{attribute_name}" do + let(:attributes) { [attribute_name, "encrypted_#{attribute_name}", "encrypted_#{attribute_name}_iv"] } + + it 'has a encrypted_attributes field' do + expect(klass.encrypted_attributes).to include(attribute_name.to_sym) + end + + it 'does not include the attribute in serializable_hash', :aggregate_failures do + attributes.each do |attribute| + expect(model.attributes).to include(attribute) # double-check the attribute does exist + + expect(model.serializable_hash).not_to include(attribute) + expect(model.to_json).not_to include(attribute) + expect(model.as_json).not_to include(attribute) + end + end + + context 'unsafe_serialization_hash option' do + it 'includes the field in serializable_hash' do + attributes.each do |attribute| + expect(model.attributes).to include(attribute) # double-check the attribute does exist + + expect(model.serializable_hash(unsafe_serialization_hash: true)).to include(attribute) + expect(model.to_json(unsafe_serialization_hash: true)).to include(attribute) + expect(model.as_json(unsafe_serialization_hash: true)).to include(attribute) + end + end + end + end + end + + it_behaves_like 'attr_encrypted attribute', WebHook, 'token' do + let_it_be(:model) { create(:system_hook) } + end + + it_behaves_like 'attr_encrypted attribute', Ci::InstanceVariable, 'value' do + let_it_be(:model) { create(:ci_instance_variable) } + end + + shared_examples "add_authentication_token_field attribute" do |klass, attribute_name, encrypted_attribute: true, digest_attribute: false| + context "#{klass.name}\##{attribute_name}" do + let(:attributes) do + if digest_attribute + ["#{attribute_name}_digest"] + elsif encrypted_attribute + [attribute_name, "#{attribute_name}_encrypted"] + else + [attribute_name] + end + end + + it 'has a add_authentication_token_field field' do + expect(klass.token_authenticatable_fields).to include(attribute_name.to_sym) + end + + it 'does not include the attribute in serializable_hash', :aggregate_failures do + attributes.each do |attribute| + expect(model.attributes).to include(attribute) # double-check the attribute does exist + + expect(model.serializable_hash).not_to include(attribute) + expect(model.to_json).not_to include(attribute) + expect(model.as_json).not_to include(attribute) + end + end + + context 'unsafe_serialization_hash option' do + it 'includes the field in serializable_hash' do + attributes.each do |attribute| + expect(model.attributes).to include(attribute) # double-check the attribute does exist + + expect(model.serializable_hash(unsafe_serialization_hash: true)).to include(attribute) + expect(model.to_json(unsafe_serialization_hash: true)).to include(attribute) + expect(model.as_json(unsafe_serialization_hash: true)).to include(attribute) + end + end + end + end + end + + it_behaves_like 'add_authentication_token_field attribute', Ci::Runner, 'token' do + let_it_be(:model) { create(:ci_runner) } + + it 'does not include token_expires_at in serializable_hash' do + attribute = 'token_expires_at' + + expect(model.attributes).to include(attribute) # double-check the attribute does exist + + expect(model.serializable_hash).not_to include(attribute) + expect(model.to_json).not_to include(attribute) + expect(model.as_json).not_to include(attribute) + end + end + + it_behaves_like 'add_authentication_token_field attribute', ApplicationSetting, 'health_check_access_token', encrypted_attribute: false do + # health_check_access_token_encrypted column does not exist + let_it_be(:model) { create(:application_setting) } + end + + it_behaves_like 'add_authentication_token_field attribute', PersonalAccessToken, 'token', encrypted_attribute: false, digest_attribute: true do + # PersonalAccessToken only has token_digest column + let_it_be(:model) { create(:personal_access_token) } + end + end +end diff --git a/spec/models/concerns/spammable_spec.rb b/spec/models/concerns/spammable_spec.rb index 5edaab56e2d..baa2d75705a 100644 --- a/spec/models/concerns/spammable_spec.rb +++ b/spec/models/concerns/spammable_spec.rb @@ -55,7 +55,7 @@ RSpec.describe Spammable do subject { invalidate_if_spam(needs_recaptcha: true) } it 'has an error related to spam on the model' do - expect(subject.errors.messages[:base]).to match_array /solve the reCAPTCHA/ + expect(subject.errors.messages[:base]).to match_array /content or solve the/ end end @@ -63,7 +63,7 @@ RSpec.describe Spammable do subject { invalidate_if_spam(is_spam: true, needs_recaptcha: true) } it 'has an error related to spam on the model' do - expect(subject.errors.messages[:base]).to match_array /solve the reCAPTCHA/ + expect(subject.errors.messages[:base]).to match_array /content or solve the/ end end diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 4534fd3664e..d7bfcc3f579 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -9,6 +9,12 @@ RSpec.shared_examples 'TokenAuthenticatable' do it { is_expected.to respond_to("set_#{token_field}") } it { is_expected.to respond_to("reset_#{token_field}!") } end + + describe 'SensitiveSerializableHash' do + it 'includes the token field in list of sensitive attributes prevented from serialization' do + expect(described_class.attributes_exempt_from_serializable_hash).to include(token_field) + end + end end RSpec.describe User, 'TokenAuthenticatable' do diff --git a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb index bccef9b9554..89ddc797a9d 100644 --- a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb +++ b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb @@ -6,6 +6,24 @@ RSpec.describe TokenAuthenticatableStrategies::Base do let(:instance) { double(:instance) } let(:field) { double(:field) } + describe '#token_fields' do + let(:strategy) { described_class.new(instance, field, options) } + let(:field) { 'some_token' } + let(:options) { {} } + + it 'includes the token field' do + expect(strategy.token_fields).to contain_exactly(field) + end + + context 'with expires_at option' do + let(:options) { { expires_at: true } } + + it 'includes the token_expires_at field' do + expect(strategy.token_fields).to contain_exactly(field, 'some_token_expires_at') + end + end + end + describe '.fabricate' do context 'when digest stragegy is specified' do it 'fabricates digest strategy object' do diff --git a/spec/models/concerns/token_authenticatable_strategies/digest_spec.rb b/spec/models/concerns/token_authenticatable_strategies/digest_spec.rb new file mode 100644 index 00000000000..bcd6e1e7316 --- /dev/null +++ b/spec/models/concerns/token_authenticatable_strategies/digest_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe TokenAuthenticatableStrategies::Digest do + let(:model) { class_double('Project') } + let(:options) { { digest: true } } + + subject(:strategy) do + described_class.new(model, 'some_field', options) + end + + describe '#token_fields' do + it 'includes the digest field' do + expect(strategy.token_fields).to contain_exactly('some_field', 'some_field_digest') + 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 458dfb47394..e0ebb86585a 100644 --- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb +++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb @@ -14,10 +14,18 @@ RSpec.describe TokenAuthenticatableStrategies::Encrypted do Gitlab::CryptoHelper.aes256_gcm_encrypt('my-value') end - subject do + subject(:strategy) do described_class.new(model, 'some_field', options) end + describe '#token_fields' do + let(:options) { { encrypted: :required } } + + it 'includes the encrypted field' do + expect(strategy.token_fields).to contain_exactly('some_field', 'some_field_encrypted') + end + end + describe '#find_token_authenticatable' do context 'when encryption is required' do let(:options) { { encrypted: :required } } |