diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-22 15:12:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-22 15:12:54 +0300 |
commit | 581c9c958dd3c7c28370f234fcb3c13c60453888 (patch) | |
tree | f12fda4b1628e142b66a7c0213a747b0d0baf4d7 /spec | |
parent | 535401c6360fbb9ff67aa72e6f9f0046f19d98ca (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
24 files changed, 235 insertions, 78 deletions
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index d684f79a518..8c2edc8cd9f 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -129,8 +129,8 @@ FactoryBot.define do { script: %w(ls), environment: { name: 'staging', - action: 'stop', - url: 'http://staging.example.com/$CI_JOB_NAME' } + action: 'stop', + url: 'http://staging.example.com/$CI_JOB_NAME' } } end end @@ -141,9 +141,9 @@ FactoryBot.define do { script: %w(ls), environment: { name: 'test_portal', - action: 'start', - url: 'http://staging.example.com/$CI_JOB_NAME', - deployment_tier: 'testing' } + action: 'start', + url: 'http://staging.example.com/$CI_JOB_NAME', + deployment_tier: 'testing' } } end end @@ -155,7 +155,7 @@ FactoryBot.define do { script: %w(ls), environment: { name: 'production', - url: 'http://prd.example.com/$CI_JOB_NAME' } + url: 'http://prd.example.com/$CI_JOB_NAME' } } end end @@ -167,8 +167,8 @@ FactoryBot.define do { script: %w(ls), environment: { name: 'review/$CI_COMMIT_REF_NAME', - url: 'http://staging.example.com/$CI_JOB_NAME', - on_stop: 'stop_review_app' } + url: 'http://staging.example.com/$CI_JOB_NAME', + on_stop: 'stop_review_app' } } end end @@ -181,8 +181,8 @@ FactoryBot.define do { script: %w(ls), environment: { name: 'review/$CI_COMMIT_REF_NAME', - url: 'http://staging.example.com/$CI_JOB_NAME', - action: 'stop' } + url: 'http://staging.example.com/$CI_JOB_NAME', + action: 'stop' } } end end diff --git a/spec/factories/environments.rb b/spec/factories/environments.rb index ccd2011eb8d..34843dab0fe 100644 --- a/spec/factories/environments.rb +++ b/spec/factories/environments.rb @@ -47,7 +47,7 @@ FactoryBot.define do pipeline = create(:ci_pipeline, project: environment.project) deployable = create(:ci_build, :success, name: "#{environment.name}:deploy", - pipeline: pipeline) + pipeline: pipeline) deployment = create(:deployment, :success, diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb index 152ae061605..6f9cf0ef895 100644 --- a/spec/factories/groups.rb +++ b/spec/factories/groups.rb @@ -106,9 +106,9 @@ FactoryBot.define do end create_graph( - parent: group, + parent: group, children: evaluator.children, - depth: evaluator.depth + depth: evaluator.depth ) end end diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index bf9f6895d24..48a6976f263 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Tooltips on .timeago dates', :js do context 'on the activity tab' do before do Event.create!( project: project, author_id: user.id, action: :joined, - updated_at: created_date, created_at: created_date) + updated_at: created_date, created_at: created_date) sign_in user visit user_activity_path(user) diff --git a/spec/features/dashboard/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb index d593031590e..a0fa53b761b 100644 --- a/spec/features/dashboard/todos/todos_sorting_spec.rb +++ b/spec/features/dashboard/todos/todos_sorting_spec.rb @@ -28,7 +28,7 @@ RSpec.describe 'Dashboard > User sorts todos' do create(:todo, user: user, project: project, target: issue_3, created_at: 3.hours.ago, updated_at: 2.minutes.ago) create(:todo, user: user, project: project, target: issue_1, created_at: 2.hours.ago, updated_at: 2.hours.ago) create(:todo, user: user, project: project, target: merge_request_1, created_at: 1.hour.ago, - updated_at: 1.hour.ago) + updated_at: 1.hour.ago) merge_request_1.labels << label_1 issue_3.labels << label_1 diff --git a/spec/features/jira_oauth_provider_authorize_spec.rb b/spec/features/jira_oauth_provider_authorize_spec.rb index a216d2d44b2..eb26440aff9 100644 --- a/spec/features/jira_oauth_provider_authorize_spec.rb +++ b/spec/features/jira_oauth_provider_authorize_spec.rb @@ -10,10 +10,10 @@ RSpec.describe 'JIRA OAuth Provider' do sign_in(user) visit oauth_jira_dvcs_authorize_path(client_id: application.uid, - redirect_uri: oauth_jira_dvcs_callback_url, - response_type: 'code', - state: 'my_state', - scope: 'read_user') + redirect_uri: oauth_jira_dvcs_callback_url, + response_type: 'code', + state: 'my_state', + scope: 'read_user') end it_behaves_like 'Secure OAuth Authorizations' diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb index c02149eed87..63ac7862b06 100644 --- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb +++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb @@ -111,7 +111,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do context 'with stop action' do let(:manual) do create(:ci_build, :manual, pipeline: pipeline, - name: 'close_app', environment: environment.name) + name: 'close_app', environment: environment.name) end before do diff --git a/spec/features/profiles/active_sessions_spec.rb b/spec/features/profiles/active_sessions_spec.rb index 24c9225532b..d0819bb5363 100644 --- a/spec/features/profiles/active_sessions_spec.rb +++ b/spec/features/profiles/active_sessions_spec.rb @@ -59,7 +59,7 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do expect(page).to( have_selector('ul.list-group li.list-group-item', text: 'Signed in on', - count: 2)) + count: 2)) expect(page).to have_content( '127.0.0.1 ' \ diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index 5c1bc1ad239..7555e567c37 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -191,7 +191,7 @@ RSpec.describe 'test coverage badge' do def show_test_coverage_badge(job: nil, min_good: nil, min_acceptable: nil, min_medium: nil) visit coverage_project_badges_path(project, ref: :master, job: job, min_good: min_good, - min_acceptable: min_acceptable, min_medium: min_medium, format: :svg) + min_acceptable: min_acceptable, min_medium: min_medium, format: :svg) end def expect_coverage_badge(coverage) diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index a53e8beb555..be4b21dfff4 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -264,9 +264,7 @@ RSpec.describe 'Environment' do let(:build) { create(:ci_build, :success, pipeline: pipeline, environment: environment.name) } let(:action) do - create(:ci_build, :manual, pipeline: pipeline, - name: 'close_app', - environment: environment.name) + create(:ci_build, :manual, pipeline: pipeline, name: 'close_app', environment: environment.name) end let(:deployment) do @@ -278,8 +276,7 @@ RSpec.describe 'Environment' do context 'when user has ability to stop environment' do let(:permissions) do - create(:protected_branch, :developers_can_merge, - name: action.ref, project: project) + create(:protected_branch, :developers_can_merge, name: action.ref, project: project) end it 'allows to stop environment', :js do diff --git a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb index 221f07a2f75..c05707d2921 100644 --- a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb +++ b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb @@ -30,8 +30,7 @@ RSpec.describe 'User sees feature flag list', :js do create(:operations_scope, strategy: strat, environment_scope: 'production') end end - create(:operations_feature_flag, :new_version_flag, project: project, - name: 'my_flag', active: false) + create(:operations_feature_flag, :new_version_flag, project: project, name: 'my_flag', active: false) end it 'shows the user the first flag' do diff --git a/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb index 71c9d89fbde..eb9ac078662 100644 --- a/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb +++ b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb @@ -18,13 +18,12 @@ RSpec.describe 'User updates feature flag', :js do context 'with a new version feature flag' do let!(:feature_flag) do - create_flag(project, 'test_flag', false, version: Operations::FeatureFlag.versions['new_version_flag'], - description: 'For testing') + create_flag(project, 'test_flag', false, + version: Operations::FeatureFlag.versions['new_version_flag'], description: 'For testing') end let!(:strategy) do - create(:operations_strategy, feature_flag: feature_flag, - name: 'default', parameters: {}) + create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {}) end let!(:scope) do diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index 289ab8cffa5..995f4a1e3d2 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -58,8 +58,7 @@ RSpec.describe 'User browses jobs' do context 'when a job can be canceled' do let!(:job) do - create(:ci_build, pipeline: pipeline, - stage: 'test') + create(:ci_build, pipeline: pipeline, stage: 'test') end before do @@ -81,7 +80,7 @@ RSpec.describe 'User browses jobs' do context 'when a job can be retried' do let!(:job) do create(:ci_build, pipeline: pipeline, - stage: 'test') + stage: 'test') end before do @@ -190,7 +189,7 @@ RSpec.describe 'User browses jobs' do context 'column links' do let!(:job) do create(:ci_build, pipeline: pipeline, - stage: 'test') + stage: 'test') end before do diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb index 2ad820e4a06..c47350fb663 100644 --- a/spec/features/projects/milestones/milestones_sorting_spec.rb +++ b/spec/features/projects/milestones/milestones_sorting_spec.rb @@ -8,7 +8,7 @@ RSpec.describe 'Milestones sorting', :js do let(:milestones_for_sort_by) do { 'Due later' => %w[b c a], - 'Name, ascending' => %w[a b c], + 'Name, ascending' => %w[a b c], 'Name, descending' => %w[c b a], 'Start later' => %w[a c b], 'Start soon' => %w[b c a], diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index f45025d079a..7cf05242a23 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -424,9 +424,10 @@ RSpec.describe 'New project', :js do it 'keeps "Import project" tab open after form validation error' do collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace) - stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return({ status: 200, - body: '001e# service=git-upload-pack', - headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } }) + stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return( + { status: 200, + body: '001e# service=git-upload-pack', + headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } }) fill_in 'project_import_url', with: 'http://foo/bar' fill_in 'project_name', with: collision_project.name @@ -465,9 +466,10 @@ RSpec.describe 'New project', :js do end it 'initiates import when valid repo url is provided' do - stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return({ status: 200, - body: '001e# service=git-upload-pack', - headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } }) + stub_request(:get, "http://foo/bar/info/refs?service=git-upload-pack").to_return( + { status: 200, + body: '001e# service=git-upload-pack', + headers: { 'Content-Type': 'application/x-git-upload-pack-advertisement' } }) fill_in 'project_import_url', with: 'http://foo/bar' diff --git a/spec/features/projects/pipelines/legacy_pipeline_spec.rb b/spec/features/projects/pipelines/legacy_pipeline_spec.rb index 14f60dfe061..f1d16f95a8c 100644 --- a/spec/features/projects/pipelines/legacy_pipeline_spec.rb +++ b/spec/features/projects/pipelines/legacy_pipeline_spec.rb @@ -769,13 +769,17 @@ RSpec.describe 'Pipeline', :js do let(:resource_group) { create(:ci_resource_group, project: project) } let!(:test_job) do - create(:ci_build, :pending, stage: 'test', name: 'test', - stage_idx: 1, pipeline: pipeline, project: project) + create(:ci_build, :pending, stage: 'test', name: 'test', stage_idx: 1, pipeline: pipeline, project: project) end let!(:deploy_job) do - create(:ci_build, :created, stage: 'deploy', name: 'deploy', - stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) + create(:ci_build, :created, + stage: 'deploy', + name: 'deploy', + stage_idx: 2, + pipeline: pipeline, + project: project, + resource_group: resource_group) end describe 'GET /:project/-/pipelines/:id' do @@ -873,8 +877,14 @@ RSpec.describe 'Pipeline', :js do context 'when deploy job is a bridge to trigger a downstream pipeline' do let!(:deploy_job) do - create(:ci_bridge, :created, stage: 'deploy', name: 'deploy', - stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) + create(:ci_bridge, :created, + stage: 'deploy', + name: 'deploy', + stage_idx: 2, + pipeline: pipeline, + project: project, + resource_group: resource_group + ) end it 'shows deploy job as waiting for resource' do @@ -895,8 +905,14 @@ RSpec.describe 'Pipeline', :js do context 'when deploy job is a bridge to trigger a downstream pipeline' do let!(:deploy_job) do - create(:ci_bridge, :created, stage: 'deploy', name: 'deploy', - stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) + create(:ci_bridge, :created, + stage: 'deploy', + name: 'deploy', + stage_idx: 2, + pipeline: pipeline, + project: project, + resource_group: resource_group + ) end it 'shows deploy job as waiting for resource' do diff --git a/spec/features/projects/pipelines/legacy_pipelines_spec.rb b/spec/features/projects/pipelines/legacy_pipelines_spec.rb index eb8f2de3aba..c903fe60fdb 100644 --- a/spec/features/projects/pipelines/legacy_pipelines_spec.rb +++ b/spec/features/projects/pipelines/legacy_pipelines_spec.rb @@ -546,8 +546,8 @@ RSpec.describe 'Pipelines', :js do context 'for a failed pipeline' do let!(:build) do create(:ci_build, :failed, pipeline: pipeline, - stage: 'build', - name: 'build') + stage: 'build', + name: 'build') end it 'displays the failure reason' do diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index cfdd851cb80..937e807b5f1 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -895,12 +895,12 @@ RSpec.describe 'Pipeline', :js do let!(:test_job) do create(:ci_build, :pending, stage: 'test', name: 'test', - stage_idx: 1, pipeline: pipeline, project: project) + stage_idx: 1, pipeline: pipeline, project: project) end let!(:deploy_job) do create(:ci_build, :created, stage: 'deploy', name: 'deploy', - stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) + stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) end describe 'GET /:project/-/pipelines/:id' do @@ -998,8 +998,14 @@ RSpec.describe 'Pipeline', :js do context 'when deploy job is a bridge to trigger a downstream pipeline' do let!(:deploy_job) do - create(:ci_bridge, :created, stage: 'deploy', name: 'deploy', - stage_idx: 2, pipeline: pipeline, project: project, resource_group: resource_group) + create(:ci_bridge, :created, + stage: 'deploy', + name: 'deploy', + stage_idx: 2, + pipeline: pipeline, + project: project, + resource_group: resource_group + ) end it 'shows deploy job as waiting for resource' do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index bf521971ae0..d4f58813534 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -536,8 +536,8 @@ RSpec.describe 'Pipelines', :js do context 'for a failed pipeline' do let!(:build) do create(:ci_build, :failed, pipeline: pipeline, - stage: 'build', - name: 'build') + stage: 'build', + name: 'build') end it 'displays the failure reason' do diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 628468a2abe..fd95516090a 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -80,7 +80,7 @@ RSpec.describe 'User creates snippet', :js do context 'when snippets default visibility level is restricted' do before do stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE], - default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE) + default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE) end it 'creates a snippet using the lowest available visibility level as default' do diff --git a/spec/features/users/email_verification_on_login_spec.rb b/spec/features/users/email_verification_on_login_spec.rb index 55954d121e1..1bfc59c3e73 100644 --- a/spec/features/users/email_verification_on_login_spec.rb +++ b/spec/features/users/email_verification_on_login_spec.rb @@ -349,9 +349,9 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting expect(Gitlab::AppLogger).to have_received(:info) .exactly(times).times .with(message || hash_including(message: 'Email Verification', - event: event, - username: user.username, - ip: '127.0.0.1', - reason: reason)) + event: event, + username: user.username, + ip: '127.0.0.1', + reason: reason)) end end diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index b875dbe1340..4c294063a4e 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -862,7 +862,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do context 'when the user already enabled 2FA' do before do user.update!(otp_required_for_login: true, - otp_secret: User.generate_otp_secret(32)) + otp_secret: User.generate_otp_secret(32)) end it 'asks the user to accept the terms' do diff --git a/spec/lib/gitlab/database/batch_count_spec.rb b/spec/lib/gitlab/database/batch_count_spec.rb index 811d4fad95c..72a4af692b4 100644 --- a/spec/lib/gitlab/database/batch_count_spec.rb +++ b/spec/lib/gitlab/database/batch_count_spec.rb @@ -86,48 +86,48 @@ RSpec.describe Gitlab::Database::BatchCount do query: batch_count_query, message: 'Query has been canceled with message: query timed out' ) - expect(subject.call(model, column, batch_size: batch_size, start: 0)).to eq(-1) + expect(subject.call(model, column, batch_size: batch_size, start: 0)).to eq(fallback) end end end describe '#batch_count' do it 'counts table' do - expect(described_class.batch_count(model)).to eq(5) + expect(described_class.batch_count(model)).to eq(model.count) end it 'counts with :id field' do - expect(described_class.batch_count(model, :id)).to eq(5) + expect(described_class.batch_count(model, :id)).to eq(model.count) end it 'counts with "id" field' do - expect(described_class.batch_count(model, 'id')).to eq(5) + expect(described_class.batch_count(model, 'id')).to eq(model.count) end it 'counts with table.id field' do - expect(described_class.batch_count(model, "#{model.table_name}.id")).to eq(5) + expect(described_class.batch_count(model, "#{model.table_name}.id")).to eq(model.count) end it 'counts with Arel column' do - expect(described_class.batch_count(model, model.arel_table[:id])).to eq(5) + expect(described_class.batch_count(model, model.arel_table[:id])).to eq(model.count) end it 'counts table with batch_size 50K' do - expect(described_class.batch_count(model, batch_size: 50_000)).to eq(5) + expect(described_class.batch_count(model, batch_size: 50_000)).to eq(model.count) end it 'will not count table with a batch size less than allowed' do expect(described_class.batch_count(model, batch_size: small_batch_size)).to eq(fallback) end - it 'counts with a small edge case batch_sizes than result' do + it 'produces the same result with different batch sizes' do stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) - [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_count(model, batch_size: i)).to eq(5) } + [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_count(model, batch_size: i)).to eq(model.count) } end it 'counts with a start and finish' do - expect(described_class.batch_count(model, start: model.minimum(:id), finish: model.maximum(:id))).to eq(5) + expect(described_class.batch_count(model, start: model.minimum(:id), finish: model.maximum(:id))).to eq(model.count) end it 'stops counting when finish value is reached' do @@ -217,6 +217,113 @@ RSpec.describe Gitlab::Database::BatchCount do end end + describe '#batch_count_with_timeout' do + it 'counts table' do + expect(described_class.batch_count_with_timeout(model)).to eq({ status: :completed, count: model.count }) + end + + it 'counts with :id field' do + expect(described_class.batch_count_with_timeout(model, :id)).to eq({ status: :completed, count: model.count }) + end + + it 'counts with "id" field' do + expect(described_class.batch_count_with_timeout(model, 'id')).to eq({ status: :completed, count: model.count }) + end + + it 'counts with table.id field' do + expect(described_class.batch_count_with_timeout(model, "#{model.table_name}.id")).to eq({ status: :completed, count: model.count }) + end + + it 'counts with Arel column' do + expect(described_class.batch_count_with_timeout(model, model.arel_table[:id])).to eq({ status: :completed, count: model.count }) + end + + it 'counts table with batch_size 50K' do + expect(described_class.batch_count_with_timeout(model, batch_size: 50_000)).to eq({ status: :completed, count: model.count }) + end + + it 'will not count table with a batch size less than allowed' do + expect(described_class.batch_count_with_timeout(model, batch_size: small_batch_size)).to eq({ status: :bad_config }) + end + + it 'produces the same result with different batch sizes' do + stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) + + [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_count_with_timeout(model, batch_size: i)).to eq({ status: :completed, count: model.count }) } + end + + it 'counts with a start and finish' do + expect(described_class.batch_count_with_timeout(model, start: model.minimum(:id), finish: model.maximum(:id))).to eq({ status: :completed, count: model.count }) + end + + it 'stops counting when finish value is reached' do + stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) + + expect(described_class.batch_count_with_timeout(model, + start: model.minimum(:id), + finish: model.maximum(:id) - 1, # Do not count the last record + batch_size: model.count - 2 # Ensure there are multiple batches + )).to eq({ status: :completed, count: model.count - 1 }) + end + + it 'returns a partial count when timeout elapses' do + stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) + + expect(::Gitlab::Metrics::System).to receive(:monotonic_time).and_return(1, 10, 300) + + expect( + described_class.batch_count_with_timeout(model, batch_size: 1, timeout: 250.seconds) + ).to eq({ status: :timeout, partial_results: 1, continue_from: model.minimum(:id) + 1 }) + end + + it 'starts counting from a given partial result' do + expect(described_class.batch_count_with_timeout(model, partial_results: 3)).to eq({ status: :completed, count: 3 + model.count }) + end + + it_behaves_like 'when a transaction is open' do + subject { described_class.batch_count_with_timeout(model) } + end + + it_behaves_like 'when batch fetch query is canceled' do + let(:mode) { :itself } + let(:operation) { :count } + let(:operation_args) { nil } + let(:column) { nil } + let(:fallback) { { status: :cancelled } } + + subject { described_class.method(:batch_count_with_timeout) } + end + + context 'disallowed_configurations' do + include_examples 'disallowed configurations', :batch_count do + let(:args) { [Issue] } + let(:default_batch_size) { Gitlab::Database::BatchCounter::DEFAULT_BATCH_SIZE } + end + + it 'raises an error if distinct count is requested' do + expect { described_class.batch_count_with_timeout(model.distinct(column)) }.to raise_error 'Use distinct count for optimized distinct counting' + end + end + + context 'when a relation is grouped' do + let!(:one_more_issue) { create(:issue, author: user, project: model.first.project) } + + before do + stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 1) + end + + context 'count by default column' do + let(:count) do + described_class.batch_count_with_timeout(model.group(column), batch_size: 2) + end + + it 'counts grouped records' do + expect(count).to eq({ status: :completed, count: { user.id => 4, another_user.id => 2 } }) + end + end + end + end + describe '#batch_distinct_count' do it 'counts with column field' do expect(described_class.batch_distinct_count(model, column)).to eq(2) @@ -242,7 +349,7 @@ RSpec.describe Gitlab::Database::BatchCount do expect(described_class.batch_distinct_count(model, column, batch_size: small_batch_size)).to eq(fallback) end - it 'counts with a small edge case batch_sizes than result' do + it 'produces the same result with different batch sizes' do stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_distinct_count(model, column, batch_size: i)).to eq(2) } diff --git a/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb b/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb index c45ec20fe5a..ee1bbafa9b5 100644 --- a/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb +++ b/spec/workers/analytics/usage_trends/counter_job_worker_spec.rb @@ -48,11 +48,43 @@ RSpec.describe Analytics::UsageTrends::CounterJobWorker do end it 'does not insert anything when BatchCount returns error' do - allow(Gitlab::Database::BatchCount).to receive(:batch_count).and_return(Gitlab::Database::BatchCounter::FALLBACK) + allow(Gitlab::Database::BatchCount).to receive(:batch_count_with_timeout) + .and_return({ status: :canceled }) expect { subject }.not_to change { Analytics::UsageTrends::Measurement.count } end + context 'when the timeout elapses' do + let(:min_id) { 1 } + let(:max_id) { 12345 } + let(:continue_from) { 321 } + let(:partial_results) { 42 } + let(:final_count) { 123 } + + subject { described_class.new.perform(users_measurement_identifier, min_id, max_id, recorded_at) } + + it 'continues counting later when the timeout elapses' do + expect(Gitlab::Database::BatchCount).to receive(:batch_count_with_timeout) + .with(anything, start: min_id, finish: max_id, timeout: 250.seconds, partial_results: nil) + .and_return({ status: :timeout, partial_results: partial_results, continue_from: continue_from }) + + expect(described_class).to receive(:perform_async).with(anything, continue_from, max_id, recorded_at, partial_results) do |*args| + described_class.new.perform(*args) + end + + expect(Gitlab::Database::BatchCount).to receive(:batch_count_with_timeout) + .with(anything, start: continue_from, finish: max_id, timeout: 250.seconds, partial_results: partial_results) + .and_return({ status: :completed, count: final_count }) + + expect { subject }.to change { Analytics::UsageTrends::Measurement.count } + + measurement = Analytics::UsageTrends::Measurement.users.last + expect(measurement.recorded_at).to be_like_time(recorded_at) + expect(measurement.identifier).to eq('users') + expect(measurement.count).to eq(final_count) + end + end + context 'when pipelines_succeeded identifier is passed' do let_it_be(:pipeline) { create(:ci_pipeline, :success) } |