summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/lib
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/shared_examples/lib')
-rw-r--r--spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb43
-rw-r--r--spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb9
-rw-r--r--spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb61
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb131
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb38
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb26
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb33
-rw-r--r--spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/lib/gitlab/json_logger_shared_examples.rb29
-rw-r--r--spec/support/shared_examples/lib/gitlab/local_and_remote_storage_migration_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/lib/gitlab/project_search_results_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb25
-rw-r--r--spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb28
-rw-r--r--spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb104
-rw-r--r--spec/support/shared_examples/lib/menus_shared_examples.rb55
-rw-r--r--spec/support/shared_examples/lib/sentry/client_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/lib/sidebars/admin/menus/admin_menus_shared_examples.rb78
-rw-r--r--spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb93
-rw-r--r--spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb52
23 files changed, 885 insertions, 75 deletions
diff --git a/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb b/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb
new file mode 100644
index 00000000000..7ace223723c
--- /dev/null
+++ b/spec/support/shared_examples/lib/api/ai_workhorse_shared_examples.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'delegates AI request to Workhorse' do |provider_flag|
+ context "when #{provider_flag} is disabled" do
+ before do
+ stub_feature_flags(provider_flag => false)
+ end
+
+ it 'responds as not found' do
+ post api(url, current_user), params: input_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when ai_experimentation_api is disabled' do
+ before do
+ stub_feature_flags(ai_experimentation_api: false)
+ end
+
+ it 'responds as not found' do
+ post api(url, current_user), params: input_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ it 'responds with Workhorse send-url headers' do
+ post api(url, current_user), params: input_params
+
+ expect(response.body).to eq('""')
+ expect(response).to have_gitlab_http_status(:ok)
+
+ send_url_prefix, encoded_data = response.headers['Gitlab-Workhorse-Send-Data'].split(':')
+ data = Gitlab::Json.parse(Base64.urlsafe_decode64(encoded_data))
+
+ expect(send_url_prefix).to eq('send-url')
+ expect(data).to eq({
+ 'AllowRedirects' => false,
+ 'Method' => 'POST'
+ }.merge(expected_params))
+ end
+end
diff --git a/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb b/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb
new file mode 100644
index 00000000000..b88eade7db2
--- /dev/null
+++ b/spec/support/shared_examples/lib/api/terraform_state_enabled_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'it depends on value of the `terraform_state.enabled` config' do |params = {}|
+ let(:expected_success_status) { params[:success_status] || :ok }
+
+ context 'when terraform_state.enabled=false' do
+ before do
+ stub_config(terraform_state: { enabled: false })
+ end
+
+ it 'returns `forbidden` response' do
+ request
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when terraform_state.enabled=true' do
+ before do
+ stub_config(terraform_state: { enabled: true })
+ end
+
+ it 'returns a successful response' do
+ request
+
+ expect(response).to have_gitlab_http_status(expected_success_status)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
index d471a758f3e..c8d62205c1e 100644
--- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/deployment_metrics.rb
@@ -1,14 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'deployment metrics examples' do
- def create_deployment(args)
- project = args[:project]
- environment = project.environments.production.first || create(:environment, :production, project: project)
- create(:deployment, :success, args.merge(environment: environment))
-
- # this is needed for the DORA API so we have aggregated data
- ::Dora::DailyMetrics::RefreshWorker.new.perform(environment.id, Time.current.to_date.to_s) if Gitlab.ee?
- end
+ include CycleAnalyticsHelpers
describe "#deploys" do
subject { stage_summary.third }
diff --git a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
index bce889b454d..5740adb3f0e 100644
--- a/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/cycle_analytics/event_shared_examples.rb
@@ -68,3 +68,64 @@ RSpec.shared_examples_for 'LEFT JOIN-able value stream analytics event' do
end
end
end
+
+RSpec.shared_examples_for 'value stream analytics first assignment event methods' do
+ let_it_be(:model1) { create(model_factory) } # rubocop: disable Rails/SaveBang
+ let_it_be(:model2) { create(model_factory) } # rubocop: disable Rails/SaveBang
+
+ let_it_be(:assignment_event1) do
+ create(event_factory, action: :add, created_at: 3.years.ago, model_factory => model1)
+ end
+
+ let_it_be(:assignment_event2) do
+ create(event_factory, action: :add, created_at: 2.years.ago, model_factory => model1)
+ end
+
+ let_it_be(:unassignment_event1) do
+ create(event_factory, action: :remove, created_at: 1.year.ago, model_factory => model1)
+ end
+
+ let(:query) { model1.class.where(id: [model1.id, model2.id]) }
+ let(:event) { described_class.new({}) }
+
+ describe '#apply_query_customization' do
+ subject(:records) { event.apply_query_customization(query).pluck(:id, *event.column_list).to_a }
+
+ it 'looks up the first assignment event timestamp' do
+ expect(records).to match_array([[model1.id, be_within(1.second).of(assignment_event1.created_at)]])
+ end
+ end
+
+ describe '#apply_negated_query_customization' do
+ subject(:records) { event.apply_negated_query_customization(query).pluck(:id).to_a }
+
+ it 'returns records where the event has not happened yet' do
+ expect(records).to eq([model2.id])
+ end
+ end
+
+ describe '#include_in' do
+ subject(:records) { event.include_in(query).pluck(:id, *event.column_list).to_a }
+
+ it 'returns both records' do
+ expect(records).to match_array([
+ [model1.id, be_within(1.second).of(assignment_event1.created_at)],
+ [model2.id, nil]
+ ])
+ end
+
+ context 'when invoked multiple times' do
+ subject(:records) do
+ scope = event.include_in(query)
+ event.include_in(scope).pluck(:id, *event.column_list).to_a
+ end
+
+ it 'returns both records' do
+ expect(records).to match_array([
+ [model1.id, be_within(1.second).of(assignment_event1.created_at)],
+ [model2.id, nil]
+ ])
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb
new file mode 100644
index 00000000000..b9d71183851
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/async_constraints_validation_shared_examples.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'async constraints validation' do
+ include ExclusiveLeaseHelpers
+
+ let!(:lease) { stub_exclusive_lease(lease_key, :uuid, timeout: lease_timeout) }
+ let(:lease_key) { "gitlab/database/asyncddl/actions/#{Gitlab::Database::PRIMARY_DATABASE_NAME}" }
+ let(:lease_timeout) { described_class::TIMEOUT_PER_ACTION }
+
+ let(:constraints_model) { Gitlab::Database::AsyncConstraints::PostgresAsyncConstraintValidation }
+ let(:table_name) { '_test_async_constraints' }
+ let(:constraint_name) { 'constraint_parent_id' }
+
+ let(:validation) do
+ create(:postgres_async_constraint_validation,
+ table_name: table_name,
+ name: constraint_name,
+ constraint_type: constraint_type)
+ end
+
+ let(:connection) { validation.connection }
+
+ subject { described_class.new(validation) }
+
+ it 'validates the constraint while controlling statement timeout' do
+ allow(connection).to receive(:execute).and_call_original
+ expect(connection).to receive(:execute)
+ .with("SET statement_timeout TO '43200s'").ordered.and_call_original
+ expect(connection).to receive(:execute)
+ .with(/ALTER TABLE "#{table_name}" VALIDATE CONSTRAINT "#{constraint_name}";/).ordered.and_call_original
+ expect(connection).to receive(:execute)
+ .with("RESET statement_timeout").ordered.and_call_original
+
+ subject.perform
+ end
+
+ it 'removes the constraint validation record from table' do
+ expect(validation).to receive(:destroy!).and_call_original
+
+ expect { subject.perform }.to change { constraints_model.count }.by(-1)
+ end
+
+ it 'skips logic if not able to acquire exclusive lease' do
+ expect(lease).to receive(:try_obtain).ordered.and_return(false)
+ expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
+ expect(validation).not_to receive(:destroy!)
+
+ expect { subject.perform }.not_to change { constraints_model.count }
+ end
+
+ it 'logs messages around execution' do
+ allow(Gitlab::AppLogger).to receive(:info).and_call_original
+
+ subject.perform
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: 'Starting to validate constraint'))
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: 'Finished validating constraint'))
+ end
+
+ context 'when the constraint does not exist' do
+ before do
+ connection.create_table(table_name, force: true)
+ end
+
+ it 'skips validation and removes the record' do
+ expect(connection).not_to receive(:execute).with(/ALTER TABLE/)
+
+ expect { subject.perform }.to change { constraints_model.count }.by(-1)
+ end
+
+ it 'logs an appropriate message' do
+ expected_message = /Skipping #{constraint_name} validation since it does not exist/
+
+ allow(Gitlab::AppLogger).to receive(:info).and_call_original
+
+ subject.perform
+
+ expect(Gitlab::AppLogger)
+ .to have_received(:info)
+ .with(a_hash_including(message: expected_message))
+ end
+ end
+
+ context 'with error handling' do
+ before do
+ allow(connection).to receive(:execute).and_call_original
+
+ allow(connection).to receive(:execute)
+ .with(/ALTER TABLE "#{table_name}" VALIDATE CONSTRAINT "#{constraint_name}";/)
+ .and_raise(ActiveRecord::StatementInvalid)
+ end
+
+ context 'on production' do
+ before do
+ allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(false)
+ end
+
+ it 'increases execution attempts' do
+ expect { subject.perform }.to change { validation.attempts }.by(1)
+
+ expect(validation.last_error).to be_present
+ expect(validation).not_to be_destroyed
+ end
+
+ it 'logs an error message including the constraint_name' do
+ expect(Gitlab::AppLogger)
+ .to receive(:error)
+ .with(a_hash_including(:message, :constraint_name))
+ .and_call_original
+
+ subject.perform
+ end
+ end
+
+ context 'on development' do
+ it 'also raises errors' do
+ expect { subject.perform }
+ .to raise_error(ActiveRecord::StatementInvalid)
+ .and change { validation.attempts }.by(1)
+
+ expect(validation.last_error).to be_present
+ expect(validation).not_to be_destroyed
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
new file mode 100644
index 00000000000..6f0cede7130
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/index_validators_shared_examples.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples "index validators" do |validator, expected_result|
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:database_indexes) do
+ [
+ ['wrong_index', 'CREATE UNIQUE INDEX wrong_index ON public.table_name (column_name)'],
+ ['extra_index', 'CREATE INDEX extra_index ON public.table_name (column_name)'],
+ ['index', 'CREATE UNIQUE INDEX "index" ON public.achievements USING btree (namespace_id, lower(name))']
+ ]
+ end
+
+ let(:inconsistency_type) { validator.name.demodulize.underscore }
+
+ let(:database_name) { 'main' }
+
+ let(:database_model) { Gitlab::Database.database_base_models[database_name] }
+
+ let(:connection) { database_model.connection }
+
+ let(:schema) { connection.current_schema }
+
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+ let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
+
+ subject(:result) { validator.new(structure_file, database).execute }
+
+ before do
+ allow(connection).to receive(:select_rows).and_return(database_indexes)
+ end
+
+ it 'returns index inconsistencies' do
+ expect(result.map(&:object_name)).to match_array(expected_result)
+ expect(result.map(&:type)).to all(eql inconsistency_type)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
new file mode 100644
index 00000000000..ec7a881f7ce
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/schema_objects_shared_examples.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples "schema objects assertions for" do |stmt_name|
+ let(:stmt) { PgQuery.parse(statement).tree.stmts.first.stmt }
+ let(:schema_object) { described_class.new(stmt.public_send(stmt_name)) }
+
+ describe '#name' do
+ it 'returns schema object name' do
+ expect(schema_object.name).to eq(name)
+ end
+ end
+
+ describe '#statement' do
+ it 'returns schema object statement' do
+ expect(schema_object.statement).to eq(statement)
+ end
+ end
+
+ describe '#table_name' do
+ it 'returns schema object table_name' do
+ expect(schema_object.table_name).to eq(table_name)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb
new file mode 100644
index 00000000000..96e58294675
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/table_validators_shared_examples.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples "table validators" do |validator, expected_result|
+ subject(:result) { validator.new(structure_file, database).execute }
+
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:inconsistency_type) { validator.name.demodulize.underscore }
+ let(:database_model) { Gitlab::Database.database_base_models['main'] }
+ let(:connection) { database_model.connection }
+ let(:schema) { connection.current_schema }
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+ let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
+ let(:database_tables) do
+ [
+ {
+ 'table_name' => 'wrong_table',
+ 'column_name' => 'id',
+ 'not_null' => true,
+ 'data_type' => 'integer',
+ 'column_default' => "nextval('audit_events_id_seq'::regclass)"
+ },
+ {
+ 'table_name' => 'wrong_table',
+ 'column_name' => 'description',
+ 'not_null' => true,
+ 'data_type' => 'character varying',
+ 'column_default' => nil
+ },
+ {
+ 'table_name' => 'extra_table',
+ 'column_name' => 'id',
+ 'not_null' => true,
+ 'data_type' => 'integer',
+ 'column_default' => "nextval('audit_events_id_seq'::regclass)"
+ },
+ {
+ 'table_name' => 'extra_table',
+ 'column_name' => 'email',
+ 'not_null' => true,
+ 'data_type' => 'character varying',
+ 'column_default' => nil
+ },
+ {
+ 'table_name' => 'extra_table_columns',
+ 'column_name' => 'id',
+ 'not_null' => true,
+ 'data_type' => 'bigint',
+ 'column_default' => "nextval('audit_events_id_seq'::regclass)"
+ },
+ {
+ 'table_name' => 'extra_table_columns',
+ 'column_name' => 'name',
+ 'not_null' => true,
+ 'data_type' => 'character varying(255)',
+ 'column_default' => nil
+ },
+ {
+ 'table_name' => 'extra_table_columns',
+ 'column_name' => 'extra_column',
+ 'not_null' => true,
+ 'data_type' => 'character varying(255)',
+ 'column_default' => nil
+ },
+ {
+ 'table_name' => 'missing_table_columns',
+ 'column_name' => 'id',
+ 'not_null' => true,
+ 'data_type' => 'bigint',
+ 'column_default' => 'NOT NULL'
+ }
+ ]
+ end
+
+ before do
+ allow(connection).to receive(:exec_query).and_return(database_tables)
+ end
+
+ it 'returns table inconsistencies' do
+ expect(result.map(&:object_name)).to match_array(expected_result)
+ expect(result.map(&:type)).to all(eql inconsistency_type)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
new file mode 100644
index 00000000000..13a112275c2
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/database/trigger_validators_shared_examples.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'trigger validators' do |validator, expected_result|
+ subject(:result) { validator.new(structure_file, database).execute }
+
+ let(:structure_file_path) { Rails.root.join('spec/fixtures/structure.sql') }
+ let(:structure_file) { Gitlab::Database::SchemaValidation::StructureSql.new(structure_file_path, schema) }
+ let(:inconsistency_type) { validator.name.demodulize.underscore }
+ let(:database_name) { 'main' }
+ let(:schema) { 'public' }
+ let(:database_model) { Gitlab::Database.database_base_models[database_name] }
+ let(:connection) { database_model.connection }
+ let(:database) { Gitlab::Database::SchemaValidation::Database.new(connection) }
+
+ let(:database_triggers) do
+ [
+ ['trigger', 'CREATE TRIGGER trigger AFTER INSERT ON public.t1 FOR EACH ROW EXECUTE FUNCTION t1()'],
+ ['wrong_trigger', 'CREATE TRIGGER wrong_trigger BEFORE UPDATE ON public.t2 FOR EACH ROW EXECUTE FUNCTION t2()'],
+ ['extra_trigger', 'CREATE TRIGGER extra_trigger BEFORE INSERT ON public.t4 FOR EACH ROW EXECUTE FUNCTION t4()']
+ ]
+ end
+
+ before do
+ allow(connection).to receive(:select_rows).and_return(database_triggers)
+ end
+
+ it 'returns trigger inconsistencies' do
+ expect(result.map(&:object_name)).to match_array(expected_result)
+ expect(result.map(&:type)).to all(eql inconsistency_type)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb
index f26b9a4a7bd..d388abb16c6 100644
--- a/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb
@@ -1,10 +1,12 @@
# frozen_string_literal: true
def raw_repo_without_container(repository)
- Gitlab::Git::Repository.new(repository.shard,
- "#{repository.disk_path}.git",
- repository.repo_type.identifier_for_container(repository.container),
- repository.container.full_path)
+ Gitlab::Git::Repository.new(
+ repository.shard,
+ "#{repository.disk_path}.git",
+ repository.repo_type.identifier_for_container(repository.container),
+ repository.container.full_path
+ )
end
RSpec.shared_examples 'Gitaly feature flag actors are inferred from repository' do
diff --git a/spec/support/shared_examples/lib/gitlab/json_logger_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/json_logger_shared_examples.rb
new file mode 100644
index 00000000000..8a5e8397c3d
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/json_logger_shared_examples.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a json logger' do |extra_params|
+ let(:now) { Time.now }
+ let(:correlation_id) { Labkit::Correlation::CorrelationId.current_id }
+
+ it 'formats strings' do
+ output = subject.format_message('INFO', now, 'test', 'Hello world')
+ data = Gitlab::Json.parse(output)
+
+ expect(data['severity']).to eq('INFO')
+ expect(data['time']).to eq(now.utc.iso8601(3))
+ expect(data['message']).to eq('Hello world')
+ expect(data['correlation_id']).to eq(correlation_id)
+ expect(data).to include(extra_params)
+ end
+
+ it 'formats hashes' do
+ output = subject.format_message('INFO', now, 'test', { hello: 1 })
+ data = Gitlab::Json.parse(output)
+
+ expect(data['severity']).to eq('INFO')
+ expect(data['time']).to eq(now.utc.iso8601(3))
+ expect(data['hello']).to eq(1)
+ expect(data['message']).to be_nil
+ expect(data['correlation_id']).to eq(correlation_id)
+ expect(data).to include(extra_params)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/local_and_remote_storage_migration_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/local_and_remote_storage_migration_shared_examples.rb
index 27ca27a9035..4b0e3234750 100644
--- a/spec/support/shared_examples/lib/gitlab/local_and_remote_storage_migration_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/local_and_remote_storage_migration_shared_examples.rb
@@ -8,9 +8,9 @@ RSpec.shared_examples 'local and remote storage migration' do
where(:start_store, :end_store, :method) do
ObjectStorage::Store::LOCAL | ObjectStorage::Store::REMOTE | :migrate_to_remote_storage
- ObjectStorage::Store::REMOTE | ObjectStorage::Store::REMOTE | :migrate_to_remote_storage # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
+ ObjectStorage::Store::REMOTE | ObjectStorage::Store::REMOTE | :migrate_to_remote_storage
ObjectStorage::Store::REMOTE | ObjectStorage::Store::LOCAL | :migrate_to_local_storage
- ObjectStorage::Store::LOCAL | ObjectStorage::Store::LOCAL | :migrate_to_local_storage # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
+ ObjectStorage::Store::LOCAL | ObjectStorage::Store::LOCAL | :migrate_to_local_storage
end
with_them do
diff --git a/spec/support/shared_examples/lib/gitlab/project_search_results_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/project_search_results_shared_examples.rb
index f83fecee4ea..0016f1e670d 100644
--- a/spec/support/shared_examples/lib/gitlab/project_search_results_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/project_search_results_shared_examples.rb
@@ -38,8 +38,7 @@ RSpec.shared_examples 'access restricted confidential issues' do
let(:user) { author }
it 'lists project confidential issues' do
- expect(objects).to contain_exactly(issue,
- security_issue_1)
+ expect(objects).to contain_exactly(issue, security_issue_1)
expect(results.limited_issues_count).to eq 2
end
end
@@ -48,8 +47,7 @@ RSpec.shared_examples 'access restricted confidential issues' do
let(:user) { assignee }
it 'lists project confidential issues for assignee' do
- expect(objects).to contain_exactly(issue,
- security_issue_2)
+ expect(objects).to contain_exactly(issue, security_issue_2)
expect(results.limited_issues_count).to eq 2
end
end
@@ -60,9 +58,7 @@ RSpec.shared_examples 'access restricted confidential issues' do
end
it 'lists project confidential issues' do
- expect(objects).to contain_exactly(issue,
- security_issue_1,
- security_issue_2)
+ expect(objects).to contain_exactly(issue, security_issue_1, security_issue_2)
expect(results.limited_issues_count).to eq 3
end
end
@@ -72,9 +68,7 @@ RSpec.shared_examples 'access restricted confidential issues' do
context 'when admin mode is enabled', :enable_admin_mode do
it 'lists all project issues' do
- expect(objects).to contain_exactly(issue,
- security_issue_1,
- security_issue_2)
+ expect(objects).to contain_exactly(issue, security_issue_1, security_issue_2)
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
index 025f0d5c7ea..c2898513424 100644
--- a/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/repo_type_shared_examples.rb
@@ -15,7 +15,7 @@ RSpec.shared_examples 'a repo type' do
describe '#repository_for' do
it 'finds the repository for the repo type' do
- expect(described_class.repository_for(expected_container)).to eq(expected_repository)
+ expect(described_class.repository_for(expected_repository_resolver)).to eq(expected_repository)
end
it 'returns nil when container is nil' do
diff --git a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
index a3e4379f4d3..18545698c27 100644
--- a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
@@ -26,29 +26,4 @@ RSpec.shared_examples 'search results filtered by language' do
expect(blob_results.size).to eq(5)
expect(paths).to match_array(expected_paths)
end
-
- context 'when the search_blobs_language_aggregation feature flag is disabled' do
- before do
- stub_feature_flags(search_blobs_language_aggregation: false)
- end
-
- it 'does not filter by language', :sidekiq_inline, :aggregate_failures do
- expected_paths = %w[
- CHANGELOG
- CONTRIBUTING.md
- bar/branch-test.txt
- custom-highlighting/test.gitlab-custom
- files/ruby/popen.rb
- files/ruby/regex.rb
- files/ruby/version_info.rb
- files/whitespace
- encoding/test.txt
- files/markdown/ruby-style-guide.md
- ]
-
- paths = blob_results.map { |blob| blob.binary_path }
- expect(blob_results.size).to eq(10)
- expect(paths).to match_array(expected_paths)
- end
- end
end
diff --git a/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
index ff03051ed37..74570a4da5c 100644
--- a/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/sidekiq_middleware/strategy_shared_examples.rb
@@ -5,7 +5,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
instance_double(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, duplicate_key_ttl: Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DEFAULT_DUPLICATE_KEY_TTL)
end
- let(:expected_message) { "dropped #{strategy_name.to_s.humanize.downcase}" }
+ let(:humanized_strategy_name) { strategy_name.to_s.humanize.downcase }
subject(:strategy) { Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies.for(strategy_name).new(fake_duplicate_job) }
@@ -155,7 +155,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
fake_logger = instance_double(Gitlab::SidekiqLogging::DeduplicationLogger)
expect(Gitlab::SidekiqLogging::DeduplicationLogger).to receive(:instance).and_return(fake_logger)
- expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, {})
+ expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), humanized_strategy_name, {})
strategy.schedule({ 'jid' => 'new jid' }) {}
end
@@ -165,7 +165,7 @@ RSpec.shared_examples 'deduplicating jobs when scheduling' do |strategy_name|
expect(Gitlab::SidekiqLogging::DeduplicationLogger).to receive(:instance).and_return(fake_logger)
allow(fake_duplicate_job).to receive(:options).and_return({ foo: :bar })
- expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), expected_message, { foo: :bar })
+ expect(fake_logger).to receive(:deduplicated_log).with(a_hash_including({ 'jid' => 'new jid' }), humanized_strategy_name, { foo: :bar })
strategy.schedule({ 'jid' => 'new jid' }) {}
end
diff --git a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
index d4802a19202..169fceced7a 100644
--- a/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/issuable_activity_shared_examples.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-RSpec.shared_examples 'a daily tracked issuable snowplow and service ping events for given event params' do
+RSpec.shared_examples 'tracked issuable snowplow and service ping events for given event params' do
before do
stub_application_setting(usage_ping_enabled: true)
end
- def count_unique(date_from: 1.minute.ago, date_to: 1.minute.from_now)
+ def count_unique(date_from: Date.today.beginning_of_week, date_to: 1.week.from_now)
Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to)
end
@@ -27,35 +27,23 @@ RSpec.shared_examples 'a daily tracked issuable snowplow and service ping events
expect_snowplow_event(**{ category: category, action: event_action, user: user1 }.merge(event_params))
end
-
- context 'with route_hll_to_snowplow_phase2 disabled' do
- before do
- stub_feature_flags(route_hll_to_snowplow_phase2: false)
- end
-
- it 'does not emit snowplow event' do
- track_action({ author: user1 }.merge(track_params))
-
- expect_no_snowplow_event
- end
- end
end
-RSpec.shared_examples 'daily tracked issuable snowplow and service ping events with project' do
- it_behaves_like 'a daily tracked issuable snowplow and service ping events for given event params' do
+RSpec.shared_examples 'tracked issuable snowplow and service ping events with project' do
+ it_behaves_like 'tracked issuable snowplow and service ping events for given event params' do
let(:context) do
Gitlab::Tracking::ServicePingContext
.new(data_source: :redis_hll, event: event_property)
.to_h
end
- let(:track_params) { { project: project } }
- let(:event_params) { track_params.merge(label: event_label, property: event_property, namespace: project.namespace, context: [context]) }
+ let(:track_params) { original_params || { project: project } }
+ let(:event_params) { { project: project }.merge(label: event_label, property: event_property, namespace: project.namespace, context: [context]) }
end
end
-RSpec.shared_examples 'a daily tracked issuable snowplow and service ping events with namespace' do
- it_behaves_like 'a daily tracked issuable snowplow and service ping events for given event params' do
+RSpec.shared_examples 'tracked issuable snowplow and service ping events with namespace' do
+ it_behaves_like 'tracked issuable snowplow and service ping events for given event params' do
let(:context) do
Gitlab::Tracking::ServicePingContext
.new(data_source: :redis_hll, event: event_property)
diff --git a/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb
new file mode 100644
index 00000000000..a42d1450e4d
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/utils/username_and_email_generator_shared_examples.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'username and email pair is generated by Gitlab::Utils::UsernameAndEmailGenerator' do
+ let(:randomhex) { 'randomhex' }
+
+ it 'check email domain' do
+ expect(subject.email).to end_with("@#{email_domain}")
+ end
+
+ it 'contains SecureRandom part' do
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+
+ expect(subject.username).to include("_#{randomhex}")
+ expect(subject.email).to include("_#{randomhex}@")
+ end
+
+ it 'email name is the same as username' do
+ expect(subject.email).to include("#{subject.username}@")
+ end
+
+ context 'when conflicts' do
+ let(:reserved_username) { "#{username_prefix}_#{randomhex}" }
+ let(:reserved_email) { "#{reserved_username}@#{email_domain}" }
+
+ shared_examples 'uniquifies username and email' do
+ it 'uniquifies username and email' do
+ expect(subject.username).to eq("#{reserved_username}1")
+ expect(subject.email).to include("#{subject.username}@")
+ end
+ end
+
+ context 'when username is reserved' do
+ context 'when username is reserved by user' do
+ before do
+ create(:user, username: reserved_username)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with top-level group namespace' do
+ before do
+ create(:group, path: reserved_username)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with top-level group namespace that includes upcased characters' do
+ before do
+ create(:group, path: reserved_username.upcase)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+ end
+
+ context 'when email is reserved' do
+ context 'when it conflicts with confirmed primary email' do
+ before do
+ create(:user, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with unconfirmed primary email' do
+ before do
+ create(:user, :unconfirmed, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+
+ context 'when it conflicts with confirmed secondary email' do
+ before do
+ create(:email, :confirmed, email: reserved_email)
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ include_examples 'uniquifies username and email'
+ end
+ end
+
+ context 'when email and username is reserved' do
+ before do
+ create(:user, email: reserved_email)
+ create(:user, username: "#{reserved_username}1")
+ allow(SecureRandom).to receive(:hex).at_least(:once).and_return(randomhex)
+ end
+
+ it 'uniquifies username and email' do
+ expect(subject.username).to eq("#{reserved_username}2")
+
+ expect(subject.email).to include("#{subject.username}@")
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/menus_shared_examples.rb b/spec/support/shared_examples/lib/menus_shared_examples.rb
index 2c2cb362b07..0aa98517444 100644
--- a/spec/support/shared_examples/lib/menus_shared_examples.rb
+++ b/spec/support/shared_examples/lib/menus_shared_examples.rb
@@ -37,3 +37,58 @@ RSpec.shared_examples_for 'pill_count formatted results' do
expect(pill_count).to eq('112.6k')
end
end
+
+RSpec.shared_examples_for 'serializable as super_sidebar_menu_args' do
+ let(:extra_attrs) { raise NotImplementedError }
+
+ it 'returns hash with provided attributes' do
+ expect(menu.serialize_as_menu_item_args).to eq({
+ title: menu.title,
+ link: menu.link,
+ active_routes: menu.active_routes,
+ container_html_options: menu.container_html_options,
+ **extra_attrs
+ })
+ end
+
+ it 'returns hash with an item_id' do
+ expect(menu.serialize_as_menu_item_args[:item_id]).not_to be_nil
+ end
+end
+
+RSpec.shared_examples_for 'not serializable as super_sidebar_menu_args' do
+ it 'returns nil' do
+ expect(menu.serialize_as_menu_item_args).to be_nil
+ end
+end
+
+RSpec.shared_examples_for 'a panel with uniquely identifiable menu items' do
+ let(:menu_items) do
+ subject.instance_variable_get(:@menus)
+ .flat_map { |menu| menu.instance_variable_get(:@items) }
+ end
+
+ it 'all menu_items have unique item_id' do
+ duplicated_ids = menu_items.group_by(&:item_id).reject { |_, v| (v.size < 2) }
+
+ expect(duplicated_ids).to eq({})
+ end
+
+ it 'all menu_items have an item_id' do
+ items_with_nil_id = menu_items.select { |item| item.item_id.nil? }
+
+ expect(items_with_nil_id).to match_array([])
+ end
+end
+
+RSpec.shared_examples_for 'a panel with all menu_items categorized' do
+ let(:uncategorized_menu) do
+ subject.instance_variable_get(:@menus)
+ .find { |menu| menu.instance_of?(::Sidebars::UncategorizedMenu) }
+ end
+
+ it 'has no uncategorized menu_items' do
+ uncategorized_menu_items = uncategorized_menu.instance_variable_get(:@items)
+ expect(uncategorized_menu_items).to eq([])
+ end
+end
diff --git a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
index e0b411e1e2a..fa3e9bf5340 100644
--- a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
+++ b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
@@ -90,7 +90,9 @@ RSpec.shared_examples 'Sentry API response size limit' do
end
it 'raises an exception when response is too large' do
- expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
- 'Sentry API response is too big. Limit is 1 MB.')
+ expect { subject }.to raise_error(
+ ErrorTracking::SentryClient::ResponseInvalidSizeError,
+ 'Sentry API response is too big. Limit is 1 MB.'
+ )
end
end
diff --git a/spec/support/shared_examples/lib/sidebars/admin/menus/admin_menus_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/admin/menus/admin_menus_shared_examples.rb
new file mode 100644
index 00000000000..f913c6b8a9e
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/admin/menus/admin_menus_shared_examples.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Admin menu' do |link:, title:, icon:, separated: false|
+ let_it_be(:user) { build(:user, :admin) }
+
+ before do
+ allow(user).to receive(:can_admin_all_resources?).and_return(true)
+ end
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'renders the correct link' do
+ expect(subject.link).to match link
+ end
+
+ it 'renders the correct title' do
+ expect(subject.title).to eq title
+ end
+
+ it 'renders the correct icon' do
+ expect(subject.sprite_icon).to be icon
+ end
+
+ it 'renders the separator if needed' do
+ expect(subject.separated?).to be separated
+ end
+
+ describe '#render?' do
+ context 'when user is admin' do
+ it 'renders' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when user is not admin' do
+ it 'does not render' do
+ expect(described_class.new(Sidebars::Context.new(current_user: build(:user),
+ container: nil)).render?).to be false
+ end
+ end
+
+ context 'when user is not logged in' do
+ it 'does not render' do
+ expect(described_class.new(Sidebars::Context.new(current_user: nil, container: nil)).render?).to be false
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Admin menu without sub menus' do |active_routes:|
+ let_it_be(:user) { build(:user, :admin) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not contain any sub menu(s)' do
+ expect(subject.has_items?).to be false
+ end
+
+ it 'defines correct active route' do
+ expect(subject.active_routes).to eq active_routes
+ end
+end
+
+RSpec.shared_examples 'Admin menu with sub menus' do
+ let_it_be(:user) { build(:user, :admin) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'contains submemus' do
+ expect(subject.has_items?).to be true
+ end
+end
diff --git a/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
new file mode 100644
index 00000000000..5e8aebb4f29
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/user_profile/user_profile_menus_shared_examples.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'User profile menu' do |title:, icon:, active_route:|
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:user) { build(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
+
+ subject { described_class.new(context) }
+
+ it 'does not contain any sub menu' do
+ expect(subject.has_items?).to be false
+ end
+
+ it 'renders the correct link' do
+ expect(subject.link).to match link
+ end
+
+ it 'renders the correct title' do
+ expect(subject.title).to eq title
+ end
+
+ it 'renders the correct icon' do
+ expect(subject.sprite_icon).to eq icon
+ end
+
+ it 'defines correct active route' do
+ expect(subject.active_routes[:path]).to be active_route
+ end
+
+ it 'renders if user is logged in' do
+ expect(subject.render?).to be true
+ end
+
+ [:blocked, :banned].each do |trait|
+ context "when viewed user is #{trait}" do
+ let_it_be(:viewed_user) { build(:user, trait) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: viewed_user) }
+
+ context 'when user is not logged in' do
+ it 'is not allowed to view the menu item' do
+ expect(described_class.new(Sidebars::Context.new(current_user: nil,
+ container: viewed_user)).render?).to be false
+ end
+ end
+
+ context 'when current user has permission' do
+ before do
+ allow(Ability).to receive(:allowed?).with(user, :read_user_profile, viewed_user).and_return(true)
+ end
+
+ it 'is allowed to view the menu item' do
+ expect(described_class.new(context).render?).to be true
+ end
+ end
+
+ context 'when current user does not have permission' do
+ it 'is not allowed to view the menu item' do
+ expect(described_class.new(context).render?).to be false
+ end
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Followers/followees counts' do |symbol|
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:user) { build(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
+
+ subject { described_class.new(context) }
+
+ context 'when there are items' do
+ before do
+ allow(user).to receive(symbol).and_return([1, 2])
+ end
+
+ it 'renders the pill' do
+ expect(subject.has_pill?).to be(true)
+ end
+
+ it 'returns the count' do
+ expect(subject.pill_count).to be(2)
+ end
+ end
+
+ context 'when there are no items' do
+ it 'does not render the pill' do
+ expect(subject.has_pill?).to be(false)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb b/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb
new file mode 100644
index 00000000000..b91386d1935
--- /dev/null
+++ b/spec/support/shared_examples/lib/sidebars/user_settings/menus/user_settings_menus_shared_examples.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'User settings menu' do |link:, title:, icon:, active_routes:|
+ let_it_be(:user) { create(:user) }
+
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ subject { described_class.new(context) }
+
+ it 'does not contain any sub menu' do
+ expect(subject.has_items?).to be false
+ end
+
+ it 'renders the correct link' do
+ expect(subject.link).to match link
+ end
+
+ it 'renders the correct title' do
+ expect(subject.title).to eq title
+ end
+
+ it 'renders the correct icon' do
+ expect(subject.sprite_icon).to be icon
+ end
+
+ it 'defines correct active route' do
+ expect(subject.active_routes).to eq active_routes
+ end
+end
+
+RSpec.shared_examples 'User settings menu #render? method' do
+ describe '#render?' do
+ subject { described_class.new(context) }
+
+ context 'when user is logged in' do
+ let_it_be(:user) { build(:user) }
+ let(:context) { Sidebars::Context.new(current_user: user, container: nil) }
+
+ it 'renders' do
+ expect(subject.render?).to be true
+ end
+ end
+
+ context 'when user is not logged in' do
+ let(:context) { Sidebars::Context.new(current_user: nil, container: nil) }
+
+ it 'does not render' do
+ expect(subject.render?).to be false
+ end
+ end
+ end
+end