diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-16 09:08:05 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-16 09:08:05 +0300 |
commit | 2bc11b8442e9f68800cfed57f9abad3f2dfc0b78 (patch) | |
tree | 373aa469b310bbd2f30dfa60ebdc2c6e18c4e4e9 /spec | |
parent | 21de0d5578ba4b6e4f7ad0667ecdaaf0810f4235 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
7 files changed, 528 insertions, 5 deletions
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index 813db12e83f..4676f56c47e 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -47,8 +47,6 @@ const ENDPOINT_METADATA_URL = `${TEST_HOST}/diff/endpointMetadata`; Vue.use(Vuex); Vue.use(VueApollo); -Vue.config.ignoredElements = ['copy-code']; - function getCollapsedFilesWarning(wrapper) { return wrapper.findComponent(CollapsedFilesWarning); } diff --git a/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/client_spec.rb new file mode 100644 index 00000000000..53bb3bda0ce --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/client_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SidekiqMiddleware::ConcurrencyLimit::Client, :clean_gitlab_redis_queues, feature_category: :global_search do + let(:worker_class) do + Class.new do + def self.name + 'TestConcurrencyLimitWorker' + end + + include ApplicationWorker + + concurrency_limit -> { 5 } + + def perform(*) + self.class.work + end + + def self.work; end + end + end + + before do + stub_const('TestConcurrencyLimitWorker', worker_class) + end + + describe '#call' do + context 'when feature flag is disabled' do + before do + stub_feature_flags(sidekiq_concurrency_limit_middleware: false) + end + + it 'schedules the job' do + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).not_to receive(:add_to_queue!) + + TestConcurrencyLimitWorker.perform_async('foo') + + expect(TestConcurrencyLimitWorker.jobs.size).to eq(1) + end + end + + context 'when there are jobs in the queue' do + before do + allow(::Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).to receive(:has_jobs_in_queue?) + .and_return(true) + end + + it 'defers the job' do + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).to receive(:add_to_queue!).once + + TestConcurrencyLimitWorker.perform_async('foo') + + expect(TestConcurrencyLimitWorker.jobs.size).to eq(0) + end + end + end +end diff --git a/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/concurrency_limit_service_spec.rb b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/concurrency_limit_service_spec.rb new file mode 100644 index 00000000000..a3922aed3a5 --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/concurrency_limit_service_spec.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService, :clean_gitlab_redis_shared_state, feature_category: :global_search do + let(:worker_class) do + Class.new do + def self.name + 'DummyWorker' + end + + include ApplicationWorker + end + end + + let(:worker_class_name) { worker_class.name } + + let(:worker_context) do + { 'correlation_id' => 'context_correlation_id', + 'meta.project' => 'gitlab-org/gitlab' } + end + + let(:stored_context) do + { + "#{Gitlab::ApplicationContext::LOG_KEY}.project" => 'gitlab-org/gitlab', + "correlation_id" => 'context_correlation_id' + } + end + + let(:worker_args) { [1, 2] } + + subject(:service) { described_class.new(worker_class_name) } + + before do + stub_const(worker_class_name, worker_class) + end + + describe '.add_to_queue!' do + subject(:add_to_queue!) { described_class.add_to_queue!(worker_class_name, worker_args, worker_context) } + + it 'calls an instance method' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:add_to_queue!).with(worker_args, worker_context) + end + + add_to_queue! + end + end + + describe '.has_jobs_in_queue?' do + it 'calls an instance method' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:has_jobs_in_queue?) + end + + described_class.has_jobs_in_queue?(worker_class_name) + end + end + + describe '.resume_processing!' do + subject(:resume_processing!) { described_class.resume_processing!(worker_class_name, limit: 10) } + + it 'calls an instance method' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:resume_processing!) + end + + resume_processing! + end + end + + describe '.queue_size' do + it 'reports the queue size' do + expect(described_class.queue_size(worker_class_name)).to eq(0) + + service.add_to_queue!(worker_args, worker_context) + + expect(described_class.queue_size(worker_class_name)).to eq(1) + + expect { service.resume_processing!(limit: 1) }.to change { described_class.queue_size(worker_class_name) }.by(-1) + end + end + + describe '#add_to_queue!' do + subject(:add_to_queue!) { service.add_to_queue!(worker_args, worker_context) } + + it 'adds a job to the set' do + expect { add_to_queue! } + .to change { service.queue_size } + .from(0).to(1) + end + + it 'adds only one unique job to the set' do + expect do + 2.times { add_to_queue! } + end.to change { service.queue_size }.from(0).to(1) + end + + it 'stores context information' do + add_to_queue! + + service.send(:with_redis) do |r| + set_key = service.send(:redis_key) + stored_job = service.send(:deserialize, r.lrange(set_key, 0, -1).first) + + expect(stored_job['context']).to eq(stored_context) + end + end + end + + describe '#has_jobs_in_queue?' do + it 'uses queue_size' do + expect { service.add_to_queue!(worker_args, worker_context) } + .to change { service.has_jobs_in_queue? } + .from(false).to(true) + end + end + + describe '#resume_processing!' do + let(:jobs) { [[1], [2], [3]] } + let(:expected_context) { stored_context.merge(related_class: described_class.name) } + + it 'puts jobs back into the queue and respects order' do + jobs.each do |j| + service.add_to_queue!(j, worker_context) + end + + expect(worker_class).to receive(:perform_async).with(1).ordered + expect(worker_class).to receive(:perform_async).with(2).ordered + expect(worker_class).not_to receive(:perform_async).with(3).ordered + + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance) + .to receive(:resumed_log) + .with(worker_class_name, [1]) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance) + .to receive(:resumed_log) + .with(worker_class_name, [2]) + + service.resume_processing!(limit: 2) + end + + it 'drops a set after execution' do + jobs.each do |j| + service.add_to_queue!(j, worker_context) + end + + expect(Gitlab::ApplicationContext).to receive(:with_raw_context) + .with(expected_context) + .exactly(jobs.count).times.and_call_original + expect(worker_class).to receive(:perform_async).exactly(jobs.count).times + + expect { service.resume_processing!(limit: jobs.count) } + .to change { service.has_jobs_in_queue? }.from(true).to(false) + end + end + + context 'with concurrent changes to different queues' do + let(:second_worker_class) do + Class.new do + def self.name + 'SecondDummyIndexingWorker' + end + + include ApplicationWorker + end + end + + let(:other_subject) { described_class.new(second_worker_class.name) } + + before do + stub_const(second_worker_class.name, second_worker_class) + end + + it 'allows to use queues independently of each other' do + expect { service.add_to_queue!(worker_args, worker_context) } + .to change { service.queue_size } + .from(0).to(1) + + expect { other_subject.add_to_queue!(worker_args, worker_context) } + .to change { other_subject.queue_size } + .from(0).to(1) + + expect { service.resume_processing!(limit: 1) }.to change { service.has_jobs_in_queue? } + .from(true).to(false) + + expect { other_subject.resume_processing!(limit: 1) }.to change { other_subject.has_jobs_in_queue? } + .from(true).to(false) + end + end +end diff --git a/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/server_spec.rb b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/server_spec.rb new file mode 100644 index 00000000000..d2c1f345b1a --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/server_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SidekiqMiddleware::ConcurrencyLimit::Server, feature_category: :global_search do + let(:worker_class) do + Class.new do + def self.name + 'TestConcurrencyLimitWorker' + end + + include ApplicationWorker + + concurrency_limit -> { 5 } + + def perform(*) + self.class.work + end + + def self.work; end + end + end + + before do + stub_const('TestConcurrencyLimitWorker', worker_class) + end + + around do |example| + with_sidekiq_server_middleware do |chain| + chain.add described_class + Sidekiq::Testing.inline! { example.run } + end + end + + describe '#call' do + context 'when feature flag is disabled' do + before do + stub_feature_flags(sidekiq_concurrency_limit_middleware: false) + end + + it 'executes the job' do + expect(TestConcurrencyLimitWorker).to receive(:work) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance).not_to receive(:deferred_log) + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).not_to receive(:add_to_queue!) + + TestConcurrencyLimitWorker.perform_async('foo') + end + end + + context 'when there are jobs in the queue' do + before do + allow(::Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).to receive(:has_jobs_in_queue?) + .and_return(true) + end + + it 'defers the job' do + expect(TestConcurrencyLimitWorker).not_to receive(:work) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance).to receive(:deferred_log).and_call_original + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).to receive(:add_to_queue!) + + TestConcurrencyLimitWorker.perform_async('foo') + end + + it 'executes the job if resumed' do + expect(TestConcurrencyLimitWorker).to receive(:work) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance).not_to receive(:deferred_log) + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).not_to receive(:add_to_queue!) + + related_class = 'Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService' + Gitlab::ApplicationContext.with_raw_context(related_class: related_class) do + TestConcurrencyLimitWorker.perform_async('foo') + end + end + end + + context 'when sidekiq_workers are stubbed' do + before do + allow(::Gitlab::SidekiqMiddleware::ConcurrencyLimit::WorkersMap).to receive(:over_the_limit?) + .and_return(over_the_limit) + end + + context 'when under the limit' do + let(:over_the_limit) { false } + + it 'executes the job' do + expect(TestConcurrencyLimitWorker).to receive(:work) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance).not_to receive(:deferred_log) + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).not_to receive(:add_to_queue!) + + TestConcurrencyLimitWorker.perform_async('foo') + end + end + + context 'when over the limit' do + let(:over_the_limit) { true } + + it 'defers the job' do + expect(TestConcurrencyLimitWorker).not_to receive(:work) + expect(Gitlab::SidekiqLogging::ConcurrencyLimitLogger.instance).to receive(:deferred_log).and_call_original + expect(Gitlab::SidekiqMiddleware::ConcurrencyLimit::ConcurrencyLimitService).to receive(:add_to_queue!) + + TestConcurrencyLimitWorker.perform_async('foo') + end + end + end + end +end diff --git a/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_concurrency_spec.rb b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_concurrency_spec.rb new file mode 100644 index 00000000000..69747dfceeb --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_concurrency_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SidekiqMiddleware::ConcurrencyLimit::WorkersConcurrency, feature_category: :global_search do + let(:worker_class) do + Class.new do + def self.name + 'TestConcurrencyLimitWorker' + end + + include ApplicationWorker + + concurrency_limit -> { 60 } + + def perform(*); end + end + end + + let(:current_concurrency) { 10 } + let(:sidekiq_worker) do + [ + 'process_id', + 'thread_id', + { + 'queue' => 'default', + 'payload' => { + 'class' => 'TestConcurrencyLimitWorker' + }.to_json + } + ] + end + + before do + stub_const('TestConcurrencyLimitWorker', worker_class) + allow(described_class).to receive(:sidekiq_workers).and_return([sidekiq_worker] * current_concurrency) + end + + describe '.current_for' do + subject(:current_for) { described_class.current_for(worker: TestConcurrencyLimitWorker, skip_cache: skip_cache) } + + context 'without cache' do + let(:skip_cache) { true } + + it 'returns the current concurrency' do + expect(described_class).to receive(:workers_uncached).and_call_original + expect(current_for).to eq(current_concurrency) + end + end + + context 'with cache' do + let(:skip_cache) { false } + let(:cached_value) { { "TestConcurrencyLimitWorker" => 20 } } + + before do + allow(Rails.cache).to receive(:fetch).and_return(cached_value) + end + + it 'returns cached current_for' do + expect(described_class).not_to receive(:workers_uncached) + + expect(current_for).to eq(20) + end + end + end + + describe '.workers' do + subject(:workers) { described_class.workers(skip_cache: skip_cache) } + + context 'without cache' do + let(:skip_cache) { true } + + it 'returns current_workers' do + expect(workers).to eq('TestConcurrencyLimitWorker' => 10) + end + end + + context 'with cache' do + let(:skip_cache) { false } + let(:cached_value) { { "TestConcurrencyLimitWorker" => 20 } } + + before do + allow(Rails.cache).to receive(:fetch).and_return(cached_value) + end + + it 'returns cached workers' do + expect(described_class).not_to receive(:workers_uncached) + + expect(workers).to eq(cached_value) + end + end + end +end diff --git a/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_map_spec.rb b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_map_spec.rb new file mode 100644 index 00000000000..3836b7f1690 --- /dev/null +++ b/spec/lib/gitlab/sidekiq_middleware/concurrency_limit/workers_map_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::SidekiqMiddleware::ConcurrencyLimit::WorkersMap, feature_category: :global_search do + let(:worker_class) do + Class.new do + def self.name + 'TestConcurrencyLimitWorker' + end + + include ApplicationWorker + + concurrency_limit -> { 60 } + + def perform(*); end + end + end + + before do + stub_const('TestConcurrencyLimitWorker', worker_class) + end + + describe '.limit_for' do + let(:expected_limit) { 60 } + + it 'accepts worker instance' do + expect(described_class.limit_for(worker: worker_class.new).call).to eq(expected_limit) + end + + it 'accepts worker class' do + expect(described_class.limit_for(worker: worker_class).call).to eq(expected_limit) + end + + it 'returns nil for unknown worker' do + expect(described_class.limit_for(worker: described_class)).to be_nil + end + + it 'returns nil if the feature flag is disabled' do + stub_feature_flags(sidekiq_concurrency_limit_middleware: false) + + expect(described_class.limit_for(worker: worker_class)).to be_nil + end + end + + describe '.over_the_limit?' do + subject(:over_the_limit?) { described_class.over_the_limit?(worker: worker_class) } + + it 'returns false if no limit is set' do + expect(described_class).to receive(:limit_for).and_return(nil) + + expect(over_the_limit?).to be_falsey + end + + it 'returns false if under the limit' do + allow(::Gitlab::SidekiqMiddleware::ConcurrencyLimit::WorkersConcurrency).to receive(:current_for).and_return(50) + + expect(over_the_limit?).to be_falsey + end + + it 'returns true if over the limit' do + allow(::Gitlab::SidekiqMiddleware::ConcurrencyLimit::WorkersConcurrency).to receive(:current_for).and_return(100) + + expect(over_the_limit?).to be_truthy + end + end + + describe '.workers' do + subject(:workers) { described_class.workers } + + it 'includes the worker' do + expect(workers).to include(worker_class) + end + end +end diff --git a/spec/lib/gitlab/tracking/event_definition_spec.rb b/spec/lib/gitlab/tracking/event_definition_spec.rb index 7c5047dc0c6..2bdf7e17c0d 100644 --- a/spec/lib/gitlab/tracking/event_definition_spec.rb +++ b/spec/lib/gitlab/tracking/event_definition_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Tracking::EventDefinition do +RSpec.describe Gitlab::Tracking::EventDefinition, feature_category: :service_ping do let(:attributes) do { description: 'Created issues', @@ -15,8 +15,10 @@ RSpec.describe Gitlab::Tracking::EventDefinition do product_stage: 'growth', product_section: 'dev', product_group: 'group::product analytics', - distribution: %w[ee ce], - tier: %w[free premium ultimate] + distributions: %w[ee ce], + tiers: %w[free premium ultimate], + introduced_by_url: "https://gitlab.com/example/-/merge_requests/123", + milestone: '1.6' } end |