diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 21:09:16 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-23 21:09:16 +0300 |
commit | f6b95a66bc12adeb4fac7277d1eb345d9e7819fd (patch) | |
tree | b2739bb34529d005a356df12da50c0e38caf6a52 /spec | |
parent | b465b2440bbf8ac8c4ef21728ab14fb48589057c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
16 files changed, 593 insertions, 308 deletions
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 5e22be1c488..c091badd09d 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -345,11 +345,23 @@ RSpec.describe Projects::BlobController do end end - it_behaves_like 'tracking unique hll events' do + context 'events tracking' do + let(:target_event) { 'g_edit_by_sfe' } + subject(:request) { put :update, params: default_params } - let(:target_event) { 'g_edit_by_sfe' } - let(:expected_value) { instance_of(Integer) } + it_behaves_like 'tracking unique hll events' do + let(:expected_value) { instance_of(Integer) } + end + + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:action) { 'perform_sfe_action' } + let(:category) { described_class.to_s } + let(:namespace) { project.namespace.reload } + let(:property) { target_event } + let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' } + let(:feature_flag_name) { 'route_hll_to_snowplow_phase4' } + end end end @@ -477,6 +489,7 @@ RSpec.describe Projects::BlobController do describe 'POST create' do let(:user) { create(:user) } + let(:target_event) { 'g_edit_by_sfe' } let(:default_params) do { namespace_id: project.namespace, @@ -498,10 +511,18 @@ RSpec.describe Projects::BlobController do subject(:request) { post :create, params: default_params } it_behaves_like 'tracking unique hll events' do - let(:target_event) { 'g_edit_by_sfe' } let(:expected_value) { instance_of(Integer) } end + it_behaves_like 'Snowplow event tracking with RedisHLL context' do + let(:action) { 'perform_sfe_action' } + let(:category) { described_class.to_s } + let(:namespace) { project.namespace } + let(:property) { target_event } + let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_sfe_edit' } + let(:feature_flag_name) { 'route_hll_to_snowplow_phase4' } + end + it 'redirects to blob' do request diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb index 5daa5b98b6e..64af25aea28 100644 --- a/spec/features/projects/user_changes_project_visibility_spec.rb +++ b/spec/features/projects/user_changes_project_visibility_spec.rb @@ -91,23 +91,4 @@ RSpec.describe 'User changes public project visibility', :js, feature_category: it_behaves_like 'does not require confirmation' end - - context 'with unlink_fork_network_upon_visibility_decrease = false' do - let(:project) { create(:project, :empty_repo, :public) } - - before do - stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false) - - fork_project(project, project.first_owner) - - sign_in(project.first_owner) - - visit edit_project_path(project) - - # https://gitlab.com/gitlab-org/gitlab/-/issues/381259 - allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110) - end - - it_behaves_like 'does not require confirmation' - end end diff --git a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js index 1d8ae6ebd3f..37392a9f1f4 100644 --- a/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js +++ b/spec/frontend/ci/runner/admin_new_runner_app/admin_new_runner_app_spec.js @@ -1,6 +1,8 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import { GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; + import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { createAlert, VARIANT_SUCCESS } from '~/flash'; @@ -85,7 +87,7 @@ describe('AdminNewRunnerApp', () => { it('pushes an alert to be shown after redirection', () => { expect(saveAlertToLocalStorage).toHaveBeenCalledWith({ - message: expect.any(String), + message: s__('Runners|Runner created.'), variant: VARIANT_SUCCESS, }); }); diff --git a/spec/helpers/analytics/cycle_analytics_helper_spec.rb b/spec/helpers/analytics/cycle_analytics_helper_spec.rb deleted file mode 100644 index d906646e25c..00000000000 --- a/spec/helpers/analytics/cycle_analytics_helper_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -RSpec.describe Analytics::CycleAnalyticsHelper do - describe '#cycle_analytics_initial_data' do - let(:user) { create(:user, name: 'fake user', username: 'fake_user') } - let(:image_path_keys) { [:empty_state_svg_path, :no_data_svg_path, :no_access_svg_path] } - let(:api_path_keys) { [:milestones_path, :labels_path] } - let(:additional_data_keys) { [:full_path, :group_id, :group_path, :project_id, :request_path] } - let(:group) { create(:group) } - - subject(:cycle_analytics_data) { helper.cycle_analytics_initial_data(project, group) } - - before do - project.add_maintainer(user) - end - - context 'when a group is present' do - let(:project) { create(:project, group: group) } - - it "sets the correct data keys" do - expect(cycle_analytics_data.keys) - .to match_array(api_path_keys + image_path_keys + additional_data_keys) - end - - it "sets group paths" do - expect(cycle_analytics_data) - .to include({ - full_path: project.full_path, - group_path: "/#{project.namespace.name}", - group_id: project.namespace.id, - request_path: "/#{project.full_path}/-/value_stream_analytics", - milestones_path: "/groups/#{group.name}/-/milestones.json", - labels_path: "/groups/#{group.name}/-/labels.json" - }) - end - end - - context 'when a group is not present' do - let(:group) { nil } - let(:project) { create(:project) } - - it "sets the correct data keys" do - expect(cycle_analytics_data.keys) - .to match_array(image_path_keys + api_path_keys + additional_data_keys) - end - - it "sets project name space paths" do - expect(cycle_analytics_data) - .to include({ - full_path: project.full_path, - group_path: project.namespace.path, - group_id: project.namespace.id, - request_path: "/#{project.full_path}/-/value_stream_analytics", - milestones_path: "/#{project.full_path}/-/milestones.json", - labels_path: "/#{project.full_path}/-/labels.json" - }) - end - end - end -end diff --git a/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb new file mode 100644 index 00000000000..6f2f1cd9124 --- /dev/null +++ b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Analytics::CycleAnalytics::RequestParams, feature_category: :value_stream_management do + it_behaves_like 'unlicensed cycle analytics request params' do + let_it_be(:user) { create(:user) } + let_it_be(:root_group) { create(:group) } + let_it_be(:project) { create(:project, group: root_group) } + + let(:namespace) { project.project_namespace } + + describe 'project-level data attributes' do + subject(:attributes) { described_class.new(params).to_data_attributes } + + it 'includes the namespace attribute' do + expect(attributes).to match(hash_including({ + namespace: { + name: project.name, + full_path: project.full_path, + avatar_url: project.avatar_url + } + })) + end + end + end +end diff --git a/spec/lib/gitlab/database/postgres_partition_spec.rb b/spec/lib/gitlab/database/postgres_partition_spec.rb index 14a4d405621..48dbdbc7757 100644 --- a/spec/lib/gitlab/database/postgres_partition_spec.rb +++ b/spec/lib/gitlab/database/postgres_partition_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::Database::PostgresPartition, type: :model do +RSpec.describe Gitlab::Database::PostgresPartition, type: :model, feature_category: :database do + let(:current_schema) { ActiveRecord::Base.connection.select_value("SELECT current_schema()") } let(:schema) { 'gitlab_partitions_dynamic' } let(:name) { '_test_partition_01' } let(:identifier) { "#{schema}.#{name}" } @@ -56,9 +57,20 @@ RSpec.describe Gitlab::Database::PostgresPartition, type: :model do expect(partitions.pluck(:name)).to eq([name, second_name]) end + it 'returns the partitions if the parent table schema is included in the table name' do + partitions = described_class.for_parent_table("#{current_schema}._test_partitioned_table") + + expect(partitions.count).to eq(2) + expect(partitions.pluck(:name)).to eq([name, second_name]) + end + it 'does not return partitions for tables not in the current schema' do expect(described_class.for_parent_table('_test_other_table').count).to eq(0) end + + it 'does not return partitions for tables if the schema is not the current' do + expect(described_class.for_parent_table('foo_bar._test_partitioned_table').count).to eq(0) + end end describe '#parent_identifier' do diff --git a/spec/lib/gitlab/database/tables_locker_spec.rb b/spec/lib/gitlab/database/tables_locker_spec.rb index d74f455eaad..1c4d6ddbf3c 100644 --- a/spec/lib/gitlab/database/tables_locker_spec.rb +++ b/spec/lib/gitlab/database/tables_locker_spec.rb @@ -2,20 +2,38 @@ require 'spec_helper' -RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base, :delete, :silence_stdout, - :suppress_gitlab_schemas_validate_connection, feature_category: :pods do - let(:detached_partition_table) { '_test_gitlab_main_part_20220101' } - let(:lock_writes_manager) do +RSpec.describe Gitlab::Database::TablesLocker, :suppress_gitlab_schemas_validate_connection, :silence_stdout, + feature_category: :pods do + let(:default_lock_writes_manager) do instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil, unlock_writes: nil) end before do - allow(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager) + allow(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(default_lock_writes_manager) + # Limiting the scope of the tests to a subset of the database tables + allow(Gitlab::Database::GitlabSchema).to receive(:tables_to_schema).and_return({ + 'application_setttings' => :gitlab_main_clusterwide, + 'projects' => :gitlab_main, + 'security_findings' => :gitlab_main, + 'ci_builds' => :gitlab_ci, + 'ci_jobs' => :gitlab_ci, + 'loose_foreign_keys_deleted_records' => :gitlab_shared, + 'ar_internal_metadata' => :gitlab_internal + }) end before(:all) do + create_partition_sql = <<~SQL + CREATE TABLE IF NOT EXISTS #{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition + PARTITION OF security_findings + FOR VALUES IN (0) + SQL + + ApplicationRecord.connection.execute(create_partition_sql) + Ci::ApplicationRecord.connection.execute(create_partition_sql) + create_detached_partition_sql = <<~SQL - CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101 ( + CREATE TABLE IF NOT EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_202201 ( id bigserial primary key not null ) SQL @@ -31,33 +49,73 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base end end - after(:all) do - drop_detached_partition_sql = <<~SQL - DROP TABLE IF EXISTS gitlab_partitions_dynamic._test_gitlab_main_part_20220101 - SQL + shared_examples "lock tables" do |gitlab_schema, database_name| + let(:connection) { Gitlab::Database.database_base_models[database_name].connection } + let(:tables_to_lock) do + Gitlab::Database::GitlabSchema + .tables_to_schema.filter_map { |table_name, schema| table_name if schema == gitlab_schema } + end - ApplicationRecord.connection.execute(drop_detached_partition_sql) - Ci::ApplicationRecord.connection.execute(drop_detached_partition_sql) + it "locks table in schema #{gitlab_schema} and database #{database_name}" do + expect(tables_to_lock).not_to be_empty - Gitlab::Database::SharedModel.using_connection(ApplicationRecord.connection) do - Postgresql::DetachedPartition.delete_all + tables_to_lock.each do |table_name| + lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil) + + expect(Gitlab::Database::LockWritesManager).to receive(:new).with( + table_name: table_name, + connection: connection, + database_name: database_name, + with_retries: true, + logger: anything, + dry_run: anything + ).once.and_return(lock_writes_manager) + expect(lock_writes_manager).to receive(:lock_writes).once + end + + subject end end - shared_examples "lock tables" do |table_schema, database_name| - let(:table_name) do + shared_examples "unlock tables" do |gitlab_schema, database_name| + let(:connection) { Gitlab::Database.database_base_models[database_name].connection } + + let(:tables_to_unlock) do Gitlab::Database::GitlabSchema - .tables_to_schema.filter_map { |table_name, schema| table_name if schema == table_schema } - .first + .tables_to_schema.filter_map { |table_name, schema| table_name if schema == gitlab_schema } end - let(:database) { database_name } + it "unlocks table in schema #{gitlab_schema} and database #{database_name}" do + expect(tables_to_unlock).not_to be_empty + + tables_to_unlock.each do |table_name| + lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, unlock_writes: nil) + + expect(Gitlab::Database::LockWritesManager).to receive(:new).with( + table_name: table_name, + connection: anything, + database_name: database_name, + with_retries: true, + logger: anything, + dry_run: anything + ).once.and_return(lock_writes_manager) + expect(lock_writes_manager).to receive(:unlock_writes) + end + + subject + end + end + + shared_examples "lock attached partitions" do |partition_identifier, database_name| + let(:connection) { Gitlab::Database.database_base_models[database_name].connection } + + it 'locks the partition' do + lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, lock_writes: nil) - it "locks table in schema #{table_schema} and database #{database_name}" do expect(Gitlab::Database::LockWritesManager).to receive(:new).with( - table_name: table_name, - connection: anything, - database_name: database, + table_name: partition_identifier, + connection: connection, + database_name: database_name, with_retries: true, logger: anything, dry_run: anything @@ -68,20 +126,16 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base end end - shared_examples "unlock tables" do |table_schema, database_name| - let(:table_name) do - Gitlab::Database::GitlabSchema - .tables_to_schema.filter_map { |table_name, schema| table_name if schema == table_schema } - .first - end + shared_examples "unlock attached partitions" do |partition_identifier, database_name| + let(:connection) { Gitlab::Database.database_base_models[database_name].connection } - let(:database) { database_name } + it 'unlocks the partition' do + lock_writes_manager = instance_double(Gitlab::Database::LockWritesManager, unlock_writes: nil) - it "unlocks table in schema #{table_schema} and database #{database_name}" do expect(Gitlab::Database::LockWritesManager).to receive(:new).with( - table_name: table_name, - connection: anything, - database_name: database, + table_name: partition_identifier, + connection: connection, + database_name: database_name, with_retries: true, logger: anything, dry_run: anything @@ -100,25 +154,29 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base describe '#lock_writes' do subject { described_class.new.lock_writes } - it 'does not call Gitlab::Database::LockWritesManager.lock_writes' do - expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager) - expect(lock_writes_manager).not_to receive(:lock_writes) + it 'does not lock any table' do + expect(Gitlab::Database::LockWritesManager).to receive(:new) + .with(any_args).and_return(default_lock_writes_manager) + expect(default_lock_writes_manager).not_to receive(:lock_writes) subject end - include_examples "unlock tables", :gitlab_main, 'main' - include_examples "unlock tables", :gitlab_ci, 'ci' - include_examples "unlock tables", :gitlab_shared, 'main' - include_examples "unlock tables", :gitlab_internal, 'main' + it_behaves_like 'unlock tables', :gitlab_main, 'main' + it_behaves_like 'unlock tables', :gitlab_ci, 'main' + it_behaves_like 'unlock tables', :gitlab_main_clusterwide, 'main' + it_behaves_like 'unlock tables', :gitlab_shared, 'main' + it_behaves_like 'unlock tables', :gitlab_internal, 'main' end describe '#unlock_writes' do subject { described_class.new.lock_writes } it 'does call Gitlab::Database::LockWritesManager.unlock_writes' do - expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager) - expect(lock_writes_manager).to receive(:unlock_writes) + expect(Gitlab::Database::LockWritesManager).to receive(:new) + .with(any_args).and_return(default_lock_writes_manager) + expect(default_lock_writes_manager).to receive(:unlock_writes) + expect(default_lock_writes_manager).not_to receive(:lock_writes) subject end @@ -133,43 +191,53 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base describe '#lock_writes' do subject { described_class.new.lock_writes } - include_examples "lock tables", :gitlab_ci, 'main' - include_examples "lock tables", :gitlab_main, 'ci' - - include_examples "unlock tables", :gitlab_main, 'main' - include_examples "unlock tables", :gitlab_ci, 'ci' - include_examples "unlock tables", :gitlab_shared, 'main' - include_examples "unlock tables", :gitlab_shared, 'ci' - include_examples "unlock tables", :gitlab_internal, 'main' - include_examples "unlock tables", :gitlab_internal, 'ci' + it_behaves_like 'lock tables', :gitlab_ci, 'main' + it_behaves_like 'lock tables', :gitlab_main, 'ci' + it_behaves_like 'lock tables', :gitlab_main_clusterwide, 'ci' + + it_behaves_like 'unlock tables', :gitlab_main_clusterwide, 'main' + it_behaves_like 'unlock tables', :gitlab_main, 'main' + it_behaves_like 'unlock tables', :gitlab_ci, 'ci' + it_behaves_like 'unlock tables', :gitlab_shared, 'main' + it_behaves_like 'unlock tables', :gitlab_shared, 'ci' + it_behaves_like 'unlock tables', :gitlab_internal, 'main' + it_behaves_like 'unlock tables', :gitlab_internal, 'ci' + + gitlab_main_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition" + it_behaves_like 'unlock attached partitions', gitlab_main_partition, 'main' + it_behaves_like 'lock attached partitions', gitlab_main_partition, 'ci' end describe '#unlock_writes' do subject { described_class.new.unlock_writes } - include_examples "unlock tables", :gitlab_ci, 'main' - include_examples "unlock tables", :gitlab_main, 'ci' - include_examples "unlock tables", :gitlab_main, 'main' - include_examples "unlock tables", :gitlab_ci, 'ci' - include_examples "unlock tables", :gitlab_shared, 'main' - include_examples "unlock tables", :gitlab_shared, 'ci' - include_examples "unlock tables", :gitlab_internal, 'main' - include_examples "unlock tables", :gitlab_internal, 'ci' + it_behaves_like "unlock tables", :gitlab_ci, 'main' + it_behaves_like "unlock tables", :gitlab_main, 'ci' + it_behaves_like "unlock tables", :gitlab_main, 'main' + it_behaves_like "unlock tables", :gitlab_ci, 'ci' + it_behaves_like "unlock tables", :gitlab_shared, 'main' + it_behaves_like "unlock tables", :gitlab_shared, 'ci' + it_behaves_like "unlock tables", :gitlab_internal, 'main' + it_behaves_like "unlock tables", :gitlab_internal, 'ci' + + gitlab_main_partition = "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.security_findings_test_partition" + it_behaves_like 'unlock attached partitions', gitlab_main_partition, 'main' + it_behaves_like 'unlock attached partitions', gitlab_main_partition, 'ci' end context 'when running in dry_run mode' do subject { described_class.new(dry_run: true).lock_writes } - it 'passes dry_run flag to LockManger' do + it 'passes dry_run flag to LockWritesManager' do expect(Gitlab::Database::LockWritesManager).to receive(:new).with( - table_name: 'users', + table_name: 'security_findings', connection: anything, database_name: 'ci', with_retries: true, logger: anything, dry_run: true - ).and_return(lock_writes_manager) - expect(lock_writes_manager).to receive(:lock_writes) + ).and_return(default_lock_writes_manager) + expect(default_lock_writes_manager).to receive(:lock_writes) subject end @@ -185,8 +253,9 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base end it 'does not lock any tables if the ci database is shared with main database' do - expect(Gitlab::Database::LockWritesManager).to receive(:new).with(any_args).and_return(lock_writes_manager) - expect(lock_writes_manager).not_to receive(:lock_writes) + expect(Gitlab::Database::LockWritesManager).to receive(:new) + .with(any_args).and_return(default_lock_writes_manager) + expect(default_lock_writes_manager).not_to receive(:lock_writes) subject end @@ -220,7 +289,3 @@ RSpec.describe Gitlab::Database::TablesLocker, :reestablished_active_record_base end end end - -def number_of_triggers(connection) - connection.select_value("SELECT count(*) FROM information_schema.triggers") -end diff --git a/spec/lib/gitlab/patch/node_loader_spec.rb b/spec/lib/gitlab/patch/node_loader_spec.rb new file mode 100644 index 00000000000..000083fc6d0 --- /dev/null +++ b/spec/lib/gitlab/patch/node_loader_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Patch::NodeLoader, feature_category: :redis do + using RSpec::Parameterized::TableSyntax + + describe '#fetch_node_info' do + let(:redis) { double(:redis) } # rubocop:disable RSpec/VerifiedDoubles + + # rubocop:disable Naming/InclusiveLanguage + where(:case_name, :args, :value) do + [ + [ + 'when only ip address is present', + "07c37df 127.0.0.1:30004@31004 slave e7d1eec 0 1426238317239 4 connected +67ed2db 127.0.0.1:30002@31002 master - 0 1426238316232 2 connected 5461-10922 +292f8b3 127.0.0.1:30003@31003 master - 0 1426238318243 3 connected 10923-16383 +6ec2392 127.0.0.1:30005@31005 slave 67ed2db 0 1426238316232 5 connected +824fe11 127.0.0.1:30006@31006 slave 292f8b3 0 1426238317741 6 connected +e7d1eec 127.0.0.1:30001@31001 myself,master - 0 0 1 connected 0-5460", + { + '127.0.0.1:30004' => 'slave', '127.0.0.1:30002' => 'master', '127.0.0.1:30003' => 'master', + '127.0.0.1:30005' => 'slave', '127.0.0.1:30006' => 'slave', '127.0.0.1:30001' => 'master' + } + ], + [ + 'when hostname is present', + "07c37df 127.0.0.1:30004@31004,host1 slave e7d1eec 0 1426238317239 4 connected +67ed2db 127.0.0.1:30002@31002,host2 master - 0 1426238316232 2 connected 5461-10922 +292f8b3 127.0.0.1:30003@31003,host3 master - 0 1426238318243 3 connected 10923-16383 +6ec2392 127.0.0.1:30005@31005,host4 slave 67ed2db 0 1426238316232 5 connected +824fe11 127.0.0.1:30006@31006,host5 slave 292f8b3 0 1426238317741 6 connected +e7d1eec 127.0.0.1:30001@31001,host6 myself,master - 0 0 1 connected 0-5460", + { + 'host1:30004' => 'slave', 'host2:30002' => 'master', 'host3:30003' => 'master', + 'host4:30005' => 'slave', 'host5:30006' => 'slave', 'host6:30001' => 'master' + } + ], + [ + 'when auxiliary fields are present', + "07c37df 127.0.0.1:30004@31004,,shard-id=69bc slave e7d1eec 0 1426238317239 4 connected +67ed2db 127.0.0.1:30002@31002,,shard-id=114f master - 0 1426238316232 2 connected 5461-10922 +292f8b3 127.0.0.1:30003@31003,,shard-id=fdb3 master - 0 1426238318243 3 connected 10923-16383 +6ec2392 127.0.0.1:30005@31005,,shard-id=114f slave 67ed2db 0 1426238316232 5 connected +824fe11 127.0.0.1:30006@31006,,shard-id=fdb3 slave 292f8b3 0 1426238317741 6 connected +e7d1eec 127.0.0.1:30001@31001,,shard-id=69bc myself,master - 0 0 1 connected 0-5460", + { + '127.0.0.1:30004' => 'slave', '127.0.0.1:30002' => 'master', '127.0.0.1:30003' => 'master', + '127.0.0.1:30005' => 'slave', '127.0.0.1:30006' => 'slave', '127.0.0.1:30001' => 'master' + } + ], + [ + 'when hostname and auxiliary fields are present', + "07c37df 127.0.0.1:30004@31004,host1,shard-id=69bc slave e7d1eec 0 1426238317239 4 connected +67ed2db 127.0.0.1:30002@31002,host2,shard-id=114f master - 0 1426238316232 2 connected 5461-10922 +292f8b3 127.0.0.1:30003@31003,host3,shard-id=fdb3 master - 0 1426238318243 3 connected 10923-16383 +6ec2392 127.0.0.1:30005@31005,host4,shard-id=114f slave 67ed2db 0 1426238316232 5 connected +824fe11 127.0.0.1:30006@31006,host5,shard-id=fdb3 slave 292f8b3 0 1426238317741 6 connected +e7d1eec 127.0.0.1:30001@31001,host6,shard-id=69bc myself,master - 0 0 1 connected 0-5460", + { + 'host1:30004' => 'slave', 'host2:30002' => 'master', 'host3:30003' => 'master', + 'host4:30005' => 'slave', 'host5:30006' => 'slave', 'host6:30001' => 'master' + } + ] + ] + end + # rubocop:enable Naming/InclusiveLanguage + + with_them do + before do + allow(redis).to receive(:call).with([:cluster, :nodes]).and_return(args) + end + + it do + expect(Redis::Cluster::NodeLoader.load_flags([redis])).to eq(value) + end + end + end +end diff --git a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb index f8a4603c1f8..c16d31cd8ef 100644 --- a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb @@ -25,12 +25,29 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red end end + it 'track snowplow event' do + track_action(author: user1, project: project) + + expect_snowplow_event( + category: described_class.name, + action: 'ide_edit', + label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit', + namespace: project.namespace, + property: event_name, + project: project, + user: user1, + context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_h] + ) + end + it 'does not track edit actions if author is not present' do expect(track_action(author: nil, project: project)).to be_nil end end context 'for web IDE edit actions' do + let(:event_name) { described_class::EDIT_BY_WEB_IDE } + it_behaves_like 'tracks and counts action' do def track_action(params) described_class.track_web_ide_edit_action(**params) @@ -43,6 +60,8 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red end context 'for SFE edit actions' do + let(:event_name) { described_class::EDIT_BY_SFE } + it_behaves_like 'tracks and counts action' do def track_action(params) described_class.track_sfe_edit_action(**params) @@ -55,6 +74,8 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red end context 'for snippet editor edit actions' do + let(:event_name) { described_class::EDIT_BY_SNIPPET_EDITOR } + it_behaves_like 'tracks and counts action' do def track_action(params) described_class.track_snippet_editor_edit_action(**params) diff --git a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb index 116948b7cb0..57d1475e564 100644 --- a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb @@ -141,6 +141,18 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do it_behaves_like 'access rights checks' end end + + context 'when instance is not configured for Google OAuth2' do + before do + stub_feature_flags(incubation_5mp_google_cloud: true) + unconfigured_google_oauth2 = Struct.new(:app_id, :app_secret).new('', '') + allow(Gitlab::Auth::OAuth::Provider).to receive(:config_for) + .with('google_oauth2') + .and_return(unconfigured_google_oauth2) + end + + it { is_expected.to be_nil } + end end end end diff --git a/spec/models/ci/runner_machine_spec.rb b/spec/models/ci/runner_machine_spec.rb index d0979d8a485..f687f7f73d6 100644 --- a/spec/models/ci/runner_machine_spec.rb +++ b/spec/models/ci/runner_machine_spec.rb @@ -54,9 +54,8 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end describe '#heartbeat', :freeze_time do - let(:runner_machine) { create(:ci_runner_machine) } + let(:runner_machine) { create(:ci_runner_machine, version: '15.0.0') } let(:executor) { 'shell' } - let(:version) { '15.0.1' } let(:values) do { ip_address: '8.8.8.8', @@ -76,18 +75,26 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model runner_machine.contacted_at = Time.current end - it 'schedules version update' do - expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version).once + context 'when version is changed' do + let(:version) { '15.0.1' } - heartbeat + before do + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version) + end - expect(runner_machine.runner_version).to be_nil - end + it 'schedules version information update' do + heartbeat - it 'updates cache' do - expect_redis_update + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once + end + + it 'updates cache' do + expect_redis_update + + heartbeat - heartbeat + expect(runner_machine.runner_version).to be_nil + end end context 'with only ip_address specified' do @@ -96,12 +103,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end it 'updates only ip_address' do - attrs = Gitlab::Json.dump(ip_address: '1.1.1.1', contacted_at: Time.current) - - Gitlab::Redis::Cache.with do |redis| - redis_key = runner_machine.send(:cache_attribute_key) - expect(redis).to receive(:set).with(redis_key, attrs, any_args) - end + expect_redis_update(values.merge(contacted_at: Time.current)) heartbeat end @@ -112,17 +114,29 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model before do runner_machine.contacted_at = 2.hours.ago - allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version).once + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version) end - context 'with invalid runner_machine' do - before do - runner_machine.runner = nil - end + context 'when version is changed' do + let(:version) { '15.0.1' } - it 'still updates redis cache and database' do - expect(runner_machine).to be_invalid + context 'with invalid runner_machine' do + before do + runner_machine.runner = nil + end + + it 'still updates redis cache and database' do + expect(runner_machine).to be_invalid + + expect_redis_update + does_db_update + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async) + .with(version).once + end + end + + it 'updates redis cache and database' do expect_redis_update does_db_update @@ -132,58 +146,52 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end context 'with unchanged runner_machine version' do - let(:runner_machine) { create(:ci_runner_machine, version: version) } + let(:version) { runner_machine.version } it 'does not schedule ci_runner_versions update' do heartbeat expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async) end - end - it 'updates redis cache and database' do - expect_redis_update - does_db_update + Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor| + context "with #{executor} executor" do + let(:executor) { executor } - expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async) - .with(version).once - end + it 'updates with expected executor type' do + expect_redis_update - Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor| - context "with #{executor} executor" do - let(:executor) { executor } + heartbeat - it 'updates with expected executor type' do - expect_redis_update - - heartbeat + expect(runner_machine.reload.read_attribute(:executor_type)).to eq(expected_executor_type) + end - expect(runner_machine.reload.read_attribute(:executor_type)).to eq(expected_executor_type) - end - - def expected_executor_type - executor.gsub(/[+-]/, '_') + def expected_executor_type + executor.gsub(/[+-]/, '_') + end end end - end - context "with an unknown executor type" do - let(:executor) { 'some-unknown-type' } + context 'with an unknown executor type' do + let(:executor) { 'some-unknown-type' } - it 'updates with unknown executor type' do - expect_redis_update + it 'updates with unknown executor type' do + expect_redis_update - heartbeat + heartbeat - expect(runner_machine.reload.read_attribute(:executor_type)).to eq('unknown') + expect(runner_machine.reload.read_attribute(:executor_type)).to eq('unknown') + end end end end - def expect_redis_update + def expect_redis_update(values = anything) + values_json = values == anything ? anything : Gitlab::Json.dump(values) + Gitlab::Redis::Cache.with do |redis| redis_key = runner_machine.send(:cache_attribute_key) - expect(redis).to receive(:set).with(redis_key, anything, any_args).and_call_original + expect(redis).to receive(:set).with(redis_key, values_json, any_args).and_call_original end end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 01d5fe7f90b..750b75684ec 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -1076,13 +1076,13 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do end end - describe '#heartbeat' do - let(:runner) { create(:ci_runner, :project) } + describe '#heartbeat', :freeze_time do + let(:runner) { create(:ci_runner, :project, version: '15.0.0') } let(:executor) { 'shell' } - let(:version) { '15.0.1' } + let(:values) { { architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version } } subject(:heartbeat) do - runner.heartbeat(architecture: '18-bit', config: { gpus: "all" }, executor: executor, version: version) + runner.heartbeat(values) end context 'when database was updated recently' do @@ -1090,27 +1090,35 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do runner.contacted_at = Time.current end - it 'updates cache' do - expect_redis_update - expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to receive(:perform_async) + context 'when version is changed' do + let(:version) { '15.0.1' } + + before do + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version) + end + + it 'updates cache' do + expect_redis_update - heartbeat + heartbeat - expect(runner.runner_version).to be_nil + expect(runner.runner_version).to be_nil + end + + it 'schedules version information update' do + heartbeat + + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once + end end context 'with only ip_address specified', :freeze_time do - subject(:heartbeat) do - runner.heartbeat(ip_address: '1.1.1.1') + let(:values) do + { ip_address: '1.1.1.1' } end it 'updates only ip_address' do - attrs = Gitlab::Json.dump(ip_address: '1.1.1.1', contacted_at: Time.current) - - Gitlab::Redis::Cache.with do |redis| - redis_key = runner.send(:cache_attribute_key) - expect(redis).to receive(:set).with(redis_key, attrs, any_args) - end + expect_redis_update(values.merge(contacted_at: Time.current)) heartbeat end @@ -1121,65 +1129,81 @@ RSpec.describe Ci::Runner, type: :model, feature_category: :runner do before do runner.contacted_at = 2.hours.ago - allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async) + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version) end - context 'with invalid runner' do - before do - runner.runner_projects.delete_all - end + context 'when version is changed' do + let(:version) { '15.0.1' } - it 'still updates redis cache and database' do - expect(runner).to be_invalid + context 'with invalid runner' do + before do + runner.runner_projects.delete_all + end + + it 'still updates redis cache and database' do + expect(runner).to be_invalid + expect_redis_update + does_db_update + + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once + end + end + + it 'updates redis cache and database' do expect_redis_update does_db_update - - expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).with(version).once end end context 'with unchanged runner version' do - let(:runner) { create(:ci_runner, version: version) } + let(:version) { runner.version } it 'does not schedule ci_runner_versions update' do heartbeat expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async) end - end - it 'updates redis cache and database' do - expect_redis_update - does_db_update - expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once - end + Ci::Runner::EXECUTOR_NAME_TO_TYPES.each_key do |executor| + context "with #{executor} executor" do + let(:executor) { executor } - %w(custom shell docker docker-windows docker-ssh ssh parallels virtualbox docker+machine docker-ssh+machine kubernetes some-unknown-type).each do |executor| - context "with #{executor} executor" do - let(:executor) { executor } + it 'updates with expected executor type' do + expect_redis_update - it 'updates with expected executor type' do - expect_redis_update + heartbeat - heartbeat + expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type) + end - expect(runner.reload.read_attribute(:executor_type)).to eq(expected_executor_type) + def expected_executor_type + executor.gsub(/[+-]/, '_') + end end + end - def expected_executor_type - return 'unknown' if executor == 'some-unknown-type' + context 'with an unknown executor type' do + let(:executor) { 'some-unknown-type' } - executor.gsub(/[+-]/, '_') + it 'updates with unknown executor type' do + expect_redis_update + + heartbeat + + expect(runner.reload.read_attribute(:executor_type)).to eq('unknown') end end end end - def expect_redis_update + def expect_redis_update(values = anything) + values_json = values == anything ? anything : Gitlab::Json.dump(values) + Gitlab::Redis::Cache.with do |redis| redis_key = runner.send(:cache_attribute_key) - expect(redis).to receive(:set).with(redis_key, anything, any_args) + expect(redis).to receive(:set).with(redis_key, values_json, any_args).and_call_original end end diff --git a/spec/requests/api/draft_notes_spec.rb b/spec/requests/api/draft_notes_spec.rb index 56b0c834010..7c56d2efc2c 100644 --- a/spec/requests/api/draft_notes_spec.rb +++ b/spec/requests/api/draft_notes_spec.rb @@ -17,7 +17,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do let!(:draft_note_by_current_user) { create(:draft_note, merge_request: merge_request, author: user) } let!(:draft_note_by_random_user) { create(:draft_note, merge_request: merge_request) } - let_it_be(:api_stub) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}" } + let_it_be(:base_url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes" } before do project.add_developer(user) @@ -25,13 +25,13 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do describe "Get a list of merge request draft notes" do it "returns 200 OK status" do - get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes", user) + get api(base_url, user) expect(response).to have_gitlab_http_status(:ok) end it "returns only draft notes authored by the current user" do - get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes", user) + get api(base_url, user) draft_note_ids = json_response.pluck("id") @@ -45,7 +45,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when requesting an existing draft note by the user" do before do get api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_current_user.id}", + "#{base_url}/#{draft_note_by_current_user.id}", user ) end @@ -61,7 +61,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when requesting a non-existent draft note" do it "returns a 404 Not Found response" do get api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{DraftNote.last.id + 1}", + "#{base_url}/#{DraftNote.last.id + 1}", user ) @@ -72,7 +72,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when requesting an existing draft note by another user" do it "returns a 404 Not Found response" do get api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_random_user.id}", + "#{base_url}/#{draft_note_by_random_user.id}", user ) @@ -88,7 +88,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do before do delete api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_current_user.id}", + "#{base_url}/#{draft_note_by_current_user.id}", user ) end @@ -105,7 +105,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when deleting a non-existent draft note" do it "returns a 404 Not Found" do delete api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{non_existing_record_id}", + "#{base_url}/#{non_existing_record_id}", user ) @@ -116,7 +116,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when deleting a draft note by a different user" do it "returns a 404 Not Found" do delete api( - "/projects/#{project.id}/merge_requests/#{merge_request.iid}/draft_notes/#{draft_note_by_random_user.id}", + "#{base_url}/#{draft_note_by_random_user.id}", user ) @@ -125,8 +125,8 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do end end - def create_draft_note(params = {}, url = api_stub) - post api("#{url}/draft_notes", user), params: params + def create_draft_note(params = {}, url = base_url) + post api(url, user), params: params end describe "Create a new draft note" do @@ -219,7 +219,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do describe "Publishing a draft note" do let(:publish_draft_note) do put api( - "#{api_stub}/draft_notes/#{draft_note_by_current_user.id}/publish", + "#{base_url}/#{draft_note_by_current_user.id}/publish", user ) end @@ -240,7 +240,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when publishing a non-existent draft note" do it "returns a 404 Not Found" do put api( - "#{api_stub}/draft_notes/#{non_existing_record_id}/publish", + "#{base_url}/#{non_existing_record_id}/publish", user ) @@ -251,7 +251,7 @@ RSpec.describe API::DraftNotes, feature_category: :code_review_workflow do context "when publishing a draft note by a different user" do it "returns a 404 Not Found" do put api( - "#{api_stub}/draft_notes/#{draft_note_by_random_user.id}/publish", + "#{base_url}/#{draft_note_by_random_user.id}/publish", user ) diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 57249bcd562..0c4f6acc262 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -227,48 +227,16 @@ RSpec.describe Projects::UpdateService do let(:user) { project.first_owner } let(:forked_project) { fork_project(project) } - context 'and unlink forks feature flag is off' do - before do - stub_feature_flags(unlink_fork_network_upon_visibility_decrease: false) - end - - it 'updates forks visibility level when parent set to more restrictive' do - opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE } - - expect(project).to be_internal - expect(forked_project).to be_internal - - expect(update_project(project, user, opts)).to eq({ status: :success }) + it 'does not change visibility of forks' do + opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE } - expect(project).to be_private - expect(forked_project.reload).to be_private - end - - it 'does not update forks visibility level when parent set to less restrictive' do - opts = { visibility_level: Gitlab::VisibilityLevel::PUBLIC } - - expect(project).to be_internal - expect(forked_project).to be_internal + expect(project).to be_internal + expect(forked_project).to be_internal - expect(update_project(project, user, opts)).to eq({ status: :success }) + expect(update_project(project, user, opts)).to eq({ status: :success }) - expect(project).to be_public - expect(forked_project.reload).to be_internal - end - end - - context 'and unlink forks feature flag is on' do - it 'does not change visibility of forks' do - opts = { visibility_level: Gitlab::VisibilityLevel::PRIVATE } - - expect(project).to be_internal - expect(forked_project).to be_internal - - expect(update_project(project, user, opts)).to eq({ status: :success }) - - expect(project).to be_private - expect(forked_project.reload).to be_internal - end + expect(project).to be_private + expect(forked_project.reload).to be_internal end end diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index d6c310d25f2..8d1e5e907c5 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -957,7 +957,6 @@ - './ee/spec/helpers/ee/geo_helper_spec.rb' - './ee/spec/helpers/ee/gitlab_routing_helper_spec.rb' - './ee/spec/helpers/ee/graph_helper_spec.rb' -- './ee/spec/helpers/ee/groups/analytics/cycle_analytics_helper_spec.rb' - './ee/spec/helpers/ee/groups/group_members_helper_spec.rb' - './ee/spec/helpers/ee/groups_helper_spec.rb' - './ee/spec/helpers/ee/groups/settings_helper_spec.rb' @@ -5084,7 +5083,6 @@ - './spec/helpers/admin/deploy_key_helper_spec.rb' - './spec/helpers/admin/identities_helper_spec.rb' - './spec/helpers/admin/user_actions_helper_spec.rb' -- './spec/helpers/analytics/cycle_analytics_helper_spec.rb' - './spec/helpers/appearances_helper_spec.rb' - './spec/helpers/application_helper_spec.rb' - './spec/helpers/application_settings_helper_spec.rb' diff --git a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb new file mode 100644 index 00000000000..9f6031af444 --- /dev/null +++ b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'unlicensed cycle analytics request params' do + let(:params) do + { + created_after: '2019-01-01', + created_before: '2019-03-01', + project_ids: [2, 3], + namespace: namespace, + current_user: user + } + end + + subject { described_class.new(params) } + + before do + root_group.add_owner(user) + end + + describe 'validations' do + it 'is valid' do + expect(subject).to be_valid + end + + context 'when `created_before` is missing' do + before do + params[:created_before] = nil + end + + it 'is valid', time_travel_to: '2019-03-01' do + expect(subject).to be_valid + end + end + + context 'when `created_before` is earlier than `created_after`' do + before do + params[:created_before] = '2015-01-01' + end + + it 'is invalid' do + expect(subject).not_to be_valid + expect(subject.errors.messages[:created_before]).not_to be_empty + end + end + + context 'when the date range exceeds 180 days' do + before do + params[:created_before] = '2019-07-15' + end + + it 'is invalid' do + expect(subject).not_to be_valid + message = s_('CycleAnalytics|The given date range is larger than 180 days') + expect(subject.errors.messages[:created_after]).to include(message) + end + end + end + + it 'casts `created_after` to `Time`' do + expect(subject.created_after).to be_a_kind_of(Time) + end + + it 'casts `created_before` to `Time`' do + expect(subject.created_before).to be_a_kind_of(Time) + end + + describe 'optional `value_stream`' do + context 'when `value_stream` is not empty' do + let(:value_stream) { instance_double('Analytics::CycleAnalytics::ValueStream') } + + before do + params[:value_stream] = value_stream + end + + it { expect(subject.value_stream).to eq(value_stream) } + end + + context 'when `value_stream` is nil' do + before do + params[:value_stream] = nil + end + + it { expect(subject.value_stream).to eq(nil) } + end + end + + describe 'sorting params' do + before do + params.merge!(sort: 'duration', direction: 'asc') + end + + it 'converts sorting params to symbol when passing it to data collector' do + data_collector_params = subject.to_data_collector_params + + expect(data_collector_params[:sort]).to eq(:duration) + expect(data_collector_params[:direction]).to eq(:asc) + end + + it 'adds sorting params to data attributes' do + data_attributes = subject.to_data_attributes + + expect(data_attributes[:sort]).to eq('duration') + expect(data_attributes[:direction]).to eq('asc') + end + end + + describe 'aggregation params' do + context 'when not licensed' do + it 'returns nil' do + data_collector_params = subject.to_data_attributes + expect(data_collector_params[:aggregation]).to eq(nil) + end + end + end + + describe 'use_aggregated_data_collector param' do + subject(:value) { described_class.new(params).to_data_collector_params[:use_aggregated_data_collector] } + + it { is_expected.to eq(false) } + end + + describe 'enable_tasks_by_type_chart data attribute' do + subject(:value) { described_class.new(params).to_data_attributes[:enable_tasks_by_type_chart] } + + it { is_expected.to eq(false) } + end +end |