summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-06 15:08:23 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-06 15:08:23 +0000
commit5472bef68de87deeb67594a98e7eb35ff83929ec (patch)
tree66e0267a3727f69ec8550d2e9b64152687d717b5 /spec
parent39c98649d20e08428f507e0728b0bd87a299e5cf (diff)
downloadgitlab-ce-5472bef68de87deeb67594a98e7eb35ff83929ec.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/jira_connect/subscriptions_controller_spec.rb18
-rw-r--r--spec/factories/groups.rb9
-rw-r--r--spec/frontend/groups/components/item_type_icon_spec.js25
-rw-r--r--spec/lib/gitlab/background_migration/batching_strategies/backfill_issue_work_item_type_batching_strategy_spec.rb136
-rw-r--r--spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb16
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb35
-rw-r--r--spec/lib/gitlab/import_export/duration_measuring_spec.rb35
-rw-r--r--spec/migrations/backfill_work_item_type_id_on_issues_spec.rb3
-rw-r--r--spec/migrations/replace_work_item_type_backfill_next_batch_strategy_spec.rb55
-rw-r--r--spec/requests/api/invitations_spec.rb2
-rw-r--r--spec/services/ci/register_job_service_spec.rb19
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb22
-rw-r--r--spec/services/members/create_service_spec.rb40
-rw-r--r--spec/services/members/invite_service_spec.rb447
-rw-r--r--spec/tasks/dev_rake_spec.rb56
-rw-r--r--spec/tasks/gitlab/setup_rake_spec.rb29
-rw-r--r--spec/workers/project_export_worker_spec.rb26
-rw-r--r--spec/workers/quality/test_data_cleanup_worker_spec.rb44
18 files changed, 807 insertions, 210 deletions
diff --git a/spec/controllers/jira_connect/subscriptions_controller_spec.rb b/spec/controllers/jira_connect/subscriptions_controller_spec.rb
index f5644a8c7c8..f548c1f399d 100644
--- a/spec/controllers/jira_connect/subscriptions_controller_spec.rb
+++ b/spec/controllers/jira_connect/subscriptions_controller_spec.rb
@@ -75,18 +75,6 @@ RSpec.describe JiraConnect::SubscriptionsController do
expect(json_response).to include('login_path' => nil)
end
end
-
- context 'with context qsh' do
- # The JSON endpoint will be requested by frontend using a JWT that Atlassian provides via Javascript.
- # This JWT will likely use a context-qsh because Atlassian don't know for which endpoint it will be used.
- # Read more about context JWT here: https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/
-
- let(:qsh) { 'context-qsh' }
-
- specify do
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
end
end
end
@@ -114,7 +102,7 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
- let(:claims) { { iss: installation.client_key, sub: 1234, qsh: 'context-qsh' } }
+ let(:claims) { { iss: installation.client_key, sub: 1234 } }
let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
let(:jira_user) { { 'groups' => { 'items' => [{ 'name' => jira_group_name }] } } }
let(:jira_group_name) { 'site-admins' }
@@ -170,7 +158,7 @@ RSpec.describe JiraConnect::SubscriptionsController do
.stub_request(:get, "#{installation.base_url}/rest/api/3/user?accountId=1234&expand=groups")
.to_return(body: jira_user.to_json, status: 200, headers: { 'Content-Type' => 'application/json' })
- delete :destroy, params: { jwt: jwt, id: subscription.id, format: :json }
+ delete :destroy, params: { jwt: jwt, id: subscription.id }
end
context 'without JWT' do
@@ -182,7 +170,7 @@ RSpec.describe JiraConnect::SubscriptionsController do
end
context 'with valid JWT' do
- let(:claims) { { iss: installation.client_key, sub: 1234, qsh: 'context-qsh' } }
+ let(:claims) { { iss: installation.client_key, sub: 1234 } }
let(:jwt) { Atlassian::Jwt.encode(claims, installation.shared_secret) }
it 'deletes the subscription' do
diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb
index aa264ad3377..152ae061605 100644
--- a/spec/factories/groups.rb
+++ b/spec/factories/groups.rb
@@ -118,14 +118,5 @@ FactoryBot.define do
create(:crm_settings, group: group, enabled: true)
end
end
-
- trait :test_group do
- path { "test-group-fulfillment#{SecureRandom.hex(4)}" }
- created_at { 4.days.ago }
-
- after(:create) do |group|
- group.add_owner(create(:user, email: "test-user-#{SecureRandom.hex(4)}@test.com"))
- end
- end
end
end
diff --git a/spec/frontend/groups/components/item_type_icon_spec.js b/spec/frontend/groups/components/item_type_icon_spec.js
index 9310943841e..fcfb4c848c6 100644
--- a/spec/frontend/groups/components/item_type_icon_spec.js
+++ b/spec/frontend/groups/components/item_type_icon_spec.js
@@ -8,7 +8,6 @@ describe('ItemTypeIcon', () => {
const defaultProps = {
itemType: ITEM_TYPE.GROUP,
- isGroupOpen: false,
};
const createComponent = (props = {}) => {
@@ -34,20 +33,14 @@ describe('ItemTypeIcon', () => {
});
it.each`
- type | isGroupOpen | icon
- ${ITEM_TYPE.GROUP} | ${true} | ${'folder-open'}
- ${ITEM_TYPE.GROUP} | ${false} | ${'folder-o'}
- ${ITEM_TYPE.PROJECT} | ${true} | ${'bookmark'}
- ${ITEM_TYPE.PROJECT} | ${false} | ${'bookmark'}
- `(
- 'shows "$icon" icon when `itemType` is "$type" and `isGroupOpen` is $isGroupOpen',
- ({ type, isGroupOpen, icon }) => {
- createComponent({
- itemType: type,
- isGroupOpen,
- });
- expect(findGlIcon().props('name')).toBe(icon);
- },
- );
+ type | icon
+ ${ITEM_TYPE.GROUP} | ${'group'}
+ ${ITEM_TYPE.PROJECT} | ${'project'}
+ `('shows "$icon" icon when `itemType` is "$type"', ({ type, icon }) => {
+ createComponent({
+ itemType: type,
+ });
+ expect(findGlIcon().props('name')).toBe(icon);
+ });
});
});
diff --git a/spec/lib/gitlab/background_migration/batching_strategies/backfill_issue_work_item_type_batching_strategy_spec.rb b/spec/lib/gitlab/background_migration/batching_strategies/backfill_issue_work_item_type_batching_strategy_spec.rb
new file mode 100644
index 00000000000..52bc2b6b18a
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/batching_strategies/backfill_issue_work_item_type_batching_strategy_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::BackfillIssueWorkItemTypeBatchingStrategy,
+ '#next_batch' do
+ # let! can't be used in migration specs because all tables but `work_item_types` are deleted after each spec
+ let!(:issue_type_enum) { { issue: 0, incident: 1, test_case: 2, requirement: 3, task: 4 } }
+ let!(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') }
+ let!(:project) { table(:projects).create!(namespace_id: namespace.id) }
+ let!(:issues_table) { table(:issues) }
+ let!(:task_type) { table(:work_item_types).find_by!(namespace_id: nil, base_type: issue_type_enum[:task]) }
+
+ let!(:issue1) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:issue]) }
+ let!(:task1) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:task]) }
+ let!(:issue2) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:issue]) }
+ let!(:issue3) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:issue]) }
+ let!(:task2) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:task]) }
+ let!(:incident1) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:incident]) }
+ # test_case is EE only, but enum values exist on the FOSS model
+ let!(:test_case1) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:test_case]) }
+
+ let!(:task3) do
+ issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:task], work_item_type_id: task_type.id)
+ end
+
+ let!(:task4) { issues_table.create!(project_id: project.id, issue_type: issue_type_enum[:task]) }
+
+ let!(:batching_strategy) { described_class.new(connection: ActiveRecord::Base.connection) }
+
+ context 'when issue_type is issue' do
+ let(:job_arguments) { [issue_type_enum[:issue], 'irrelevant_work_item_id'] }
+
+ context 'when starting on the first batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = next_batch(issue1.id, 2)
+
+ expect(batch_bounds).to match_array([issue1.id, issue2.id])
+ end
+ end
+
+ context 'when additional batches remain' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = next_batch(issue2.id, 2)
+
+ expect(batch_bounds).to match_array([issue2.id, issue3.id])
+ end
+ end
+
+ context 'when on the final batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = next_batch(issue3.id, 2)
+
+ expect(batch_bounds).to match_array([issue3.id, issue3.id])
+ end
+ end
+
+ context 'when no additional batches remain' do
+ it 'returns nil' do
+ batch_bounds = next_batch(issue3.id + 1, 1)
+
+ expect(batch_bounds).to be_nil
+ end
+ end
+ end
+
+ context 'when issue_type is incident' do
+ let(:job_arguments) { [issue_type_enum[:incident], 'irrelevant_work_item_id'] }
+
+ context 'when starting on the first batch' do
+ it 'returns the bounds of the next batch with only one element' do
+ batch_bounds = next_batch(incident1.id, 2)
+
+ expect(batch_bounds).to match_array([incident1.id, incident1.id])
+ end
+ end
+ end
+
+ context 'when issue_type is requirement and there are no matching records' do
+ let(:job_arguments) { [issue_type_enum[:requirement], 'irrelevant_work_item_id'] }
+
+ context 'when starting on the first batch' do
+ it 'returns nil' do
+ batch_bounds = next_batch(1, 2)
+
+ expect(batch_bounds).to be_nil
+ end
+ end
+ end
+
+ context 'when issue_type is task' do
+ let(:job_arguments) { [issue_type_enum[:task], 'irrelevant_work_item_id'] }
+
+ context 'when starting on the first batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = next_batch(task1.id, 2)
+
+ expect(batch_bounds).to match_array([task1.id, task2.id])
+ end
+ end
+
+ context 'when additional batches remain' do
+ it 'returns the bounds of the next batch, does not skip records where FK is already set' do
+ batch_bounds = next_batch(task2.id, 2)
+
+ expect(batch_bounds).to match_array([task2.id, task3.id])
+ end
+ end
+
+ context 'when on the final batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = next_batch(task4.id, 2)
+
+ expect(batch_bounds).to match_array([task4.id, task4.id])
+ end
+ end
+
+ context 'when no additional batches remain' do
+ it 'returns nil' do
+ batch_bounds = next_batch(task4.id + 1, 1)
+
+ expect(batch_bounds).to be_nil
+ end
+ end
+ end
+
+ def next_batch(min_value, batch_size)
+ batching_strategy.next_batch(
+ :issues,
+ :id,
+ batch_min_value: min_value,
+ batch_size: batch_size,
+ job_arguments: job_arguments
+ )
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb b/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb
index 9fab1922cb7..521e2067744 100644
--- a/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb
+++ b/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
context 'when starting on the first batch' do
it 'returns the bounds of the next batch' do
- batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace1.id, batch_size: 3, job_arguments: nil)
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace1.id, batch_size: 3, job_arguments: [])
expect(batch_bounds).to eq([namespace1.id, namespace3.id])
end
@@ -23,7 +23,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
context 'when additional batches remain' do
it 'returns the bounds of the next batch' do
- batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace2.id, batch_size: 3, job_arguments: nil)
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace2.id, batch_size: 3, job_arguments: [])
expect(batch_bounds).to eq([namespace2.id, namespace4.id])
end
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
context 'when on the final batch' do
it 'returns the bounds of the next batch' do
- batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3, job_arguments: nil)
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3, job_arguments: [])
expect(batch_bounds).to eq([namespace4.id, namespace4.id])
end
@@ -39,7 +39,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
context 'when no additional batches remain' do
it 'returns nil' do
- batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id + 1, batch_size: 1, job_arguments: nil)
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id + 1, batch_size: 1, job_arguments: [])
expect(batch_bounds).to be_nil
end
@@ -48,8 +48,10 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
context 'additional filters' do
let(:strategy_with_filters) do
Class.new(described_class) do
- def apply_additional_filters(relation)
- relation.where.not(type: 'Project')
+ def apply_additional_filters(relation, job_arguments:)
+ min_id = job_arguments.first
+
+ relation.where.not(type: 'Project').where('id >= ?', min_id)
end
end
end
@@ -58,7 +60,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
let!(:namespace5) { namespaces.create!(name: 'batchtest5', path: 'batch-test5', type: 'Project') }
it 'applies additional filters' do
- batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3, job_arguments: nil)
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3, job_arguments: [1])
expect(batch_bounds).to eq([namespace4.id, namespace4.id])
end
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index 2b63f44ddcc..7a433be0e2f 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -79,12 +79,23 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
describe '.active_migration' do
let!(:migration1) { create(:batched_background_migration, :finished) }
- let!(:migration2) { create(:batched_background_migration, :active) }
- let!(:migration3) { create(:batched_background_migration, :active) }
- it 'returns the first active migration according to queue order' do
- expect(described_class.active_migration).to eq(migration2)
- create(:batched_background_migration_job, :succeeded, batched_migration: migration1, batch_size: 1000)
+ context 'without migrations on hold' do
+ let!(:migration2) { create(:batched_background_migration, :active) }
+ let!(:migration3) { create(:batched_background_migration, :active) }
+
+ it 'returns the first active migration according to queue order' do
+ expect(described_class.active_migration).to eq(migration2)
+ end
+ end
+
+ context 'with migrations are on hold' do
+ let!(:migration2) { create(:batched_background_migration, :active, on_hold_until: 10.minutes.from_now) }
+ let!(:migration3) { create(:batched_background_migration, :active, on_hold_until: 2.minutes.ago) }
+
+ it 'returns the first active migration that is not on hold according to queue order' do
+ expect(described_class.active_migration).to eq(migration3)
+ end
end
end
@@ -518,6 +529,20 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
end
end
+ describe '#hold!', :freeze_time do
+ subject { create(:batched_background_migration) }
+
+ let(:time) { 5.minutes.from_now }
+
+ it 'updates on_hold_until property' do
+ expect { subject.hold!(until_time: time) }.to change { subject.on_hold_until }.from(nil).to(time)
+ end
+
+ it 'defaults to 10 minutes' do
+ expect { subject.hold! }.to change { subject.on_hold_until }.from(nil).to(10.minutes.from_now)
+ end
+ end
+
describe '.for_configuration' do
let!(:migration) do
create(
diff --git a/spec/lib/gitlab/import_export/duration_measuring_spec.rb b/spec/lib/gitlab/import_export/duration_measuring_spec.rb
new file mode 100644
index 00000000000..cf8b6060741
--- /dev/null
+++ b/spec/lib/gitlab/import_export/duration_measuring_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::ImportExport::DurationMeasuring do
+ subject do
+ Class.new do
+ include Gitlab::ImportExport::DurationMeasuring
+
+ def test
+ with_duration_measuring do
+ 'test'
+ end
+ end
+ end.new
+ end
+
+ it 'measures method execution duration' do
+ subject.test
+
+ expect(subject.duration_s).not_to be_nil
+ end
+
+ describe '#with_duration_measuring' do
+ it 'yields control' do
+ expect { |block| subject.with_duration_measuring(&block) }.to yield_control
+ end
+
+ it 'returns result of the yielded block' do
+ return_value = 'return_value'
+
+ expect(subject.with_duration_measuring { return_value }).to eq(return_value)
+ end
+ end
+end
diff --git a/spec/migrations/backfill_work_item_type_id_on_issues_spec.rb b/spec/migrations/backfill_work_item_type_id_on_issues_spec.rb
index ca7bf909583..6798b0cc7e8 100644
--- a/spec/migrations/backfill_work_item_type_id_on_issues_spec.rb
+++ b/spec/migrations/backfill_work_item_type_id_on_issues_spec.rb
@@ -32,7 +32,8 @@ RSpec.describe BackfillWorkItemTypeIdOnIssues, :migration do
interval: interval,
batch_size: described_class::BATCH_SIZE,
max_batch_size: described_class::MAX_BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE
+ sub_batch_size: described_class::SUB_BATCH_SIZE,
+ batch_class_name: described_class::BATCH_CLASS_NAME
)
end
end
diff --git a/spec/migrations/replace_work_item_type_backfill_next_batch_strategy_spec.rb b/spec/migrations/replace_work_item_type_backfill_next_batch_strategy_spec.rb
new file mode 100644
index 00000000000..5e22fc06973
--- /dev/null
+++ b/spec/migrations/replace_work_item_type_backfill_next_batch_strategy_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ReplaceWorkItemTypeBackfillNextBatchStrategy, :migration do
+ describe '#up' do
+ it 'sets the new strategy for existing migrations' do
+ migrations = create_migrations(described_class::OLD_STRATEGY_CLASS, 2)
+
+ expect do
+ migrate!
+
+ migrations.each(&:reload)
+ end.to change { migrations.pluck(:batch_class_name).uniq }.from([described_class::OLD_STRATEGY_CLASS])
+ .to([described_class::NEW_STRATEGY_CLASS])
+ end
+ end
+
+ describe '#down' do
+ it 'sets the old strategy for existing migrations' do
+ migrations = create_migrations(described_class::NEW_STRATEGY_CLASS, 2)
+
+ expect do
+ migrate!
+ schema_migrate_down!
+
+ migrations.each(&:reload)
+ end.to change { migrations.pluck(:batch_class_name).uniq }.from([described_class::NEW_STRATEGY_CLASS])
+ .to([described_class::OLD_STRATEGY_CLASS])
+ end
+ end
+
+ def create_migrations(batch_class_name, count)
+ Array.new(2) { |index| create_background_migration(batch_class_name, [index]) }
+ end
+
+ def create_background_migration(batch_class_name, job_arguments)
+ migrations_table = table(:batched_background_migrations)
+
+ migrations_table.create!(
+ batch_class_name: batch_class_name,
+ job_class_name: described_class::JOB_CLASS_NAME,
+ max_value: 10,
+ batch_size: 5,
+ sub_batch_size: 1,
+ interval: 2.minutes,
+ table_name: :issues,
+ column_name: :id,
+ total_tuple_count: 10_000,
+ pause_ms: 100,
+ job_arguments: job_arguments
+ )
+ end
+end
diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb
index 0b9524a7ee7..e6cb7f1a07e 100644
--- a/spec/requests/api/invitations_spec.rb
+++ b/spec/requests/api/invitations_spec.rb
@@ -240,7 +240,7 @@ RSpec.describe API::Invitations do
params: { email: '', access_level: Member::MAINTAINER }
expect(response).to have_gitlab_http_status(:created)
- expect(json_response['message']).to eq('Emails cannot be blank')
+ expect(json_response['message']).to eq('Invites cannot be blank')
end
it 'returns 404 when the email list is not a valid format' do
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 2e1f86605e8..74adbc4efc8 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -785,6 +785,25 @@ module Ci
include_examples 'handles runner assignment'
end
+
+ context 'when a conflicting data is stored in denormalized table' do
+ let!(:specific_runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[conflict]) }
+ let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[conflict]) }
+
+ before do
+ pending_job.update_column(:status, :running)
+ end
+
+ it 'removes queuing entry upon build assignment attempt' do
+ expect(pending_job.reload).to be_running
+ expect(pending_job.queuing_entry).to be_present
+
+ result = described_class.new(specific_runner).execute
+
+ expect(result).not_to be_valid
+ expect(pending_job.reload.queuing_entry).not_to be_present
+ end
+ end
end
context 'when not using pending builds table' do
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index ef43866d8d4..d3f537a1aa0 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -103,6 +103,28 @@ RSpec.describe Ci::UpdateBuildQueueService do
end
end
end
+
+ describe '#remove!' do
+ context 'when pending build exists' do
+ before do
+ create(:ci_pending_build, build: build, project: build.project)
+ end
+
+ it 'removes pending build in a transaction' do
+ dequeued = subject.remove!(build)
+
+ expect(dequeued).to eq build.id
+ end
+ end
+
+ context 'when pending build does not exist' do
+ it 'does nothing if there is no pending build to remove' do
+ dequeued = subject.remove!(build)
+
+ expect(dequeued).to be_nil
+ end
+ end
+ end
end
describe 'shared runner builds tracking' do
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 4396a0d3ec3..05975d4d875 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_
let_it_be(:source, reload: true) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:member) { create(:user) }
+ let_it_be(:user_invited_by_id) { create(:user) }
let_it_be(:user_ids) { member.id.to_s }
let_it_be(:access_level) { Gitlab::Access::GUEST }
@@ -49,6 +50,36 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_
expect(OnboardingProgress.completed?(source.namespace, :user_added)).to be(true)
end
+ context 'when user_id is passed as an integer' do
+ let(:user_ids) { member.id }
+
+ it 'successfully creates member' do
+ expect(execute_service[:status]).to eq(:success)
+ expect(source.users).to include member
+ expect(OnboardingProgress.completed?(source.namespace, :user_added)).to be(true)
+ end
+ end
+
+ context 'with user_ids as an array of integers' do
+ let(:user_ids) { [member.id, user_invited_by_id.id] }
+
+ it 'successfully creates members' do
+ expect(execute_service[:status]).to eq(:success)
+ expect(source.users).to include(member, user_invited_by_id)
+ expect(OnboardingProgress.completed?(source.namespace, :user_added)).to be(true)
+ end
+ end
+
+ context 'with user_ids as an array of strings' do
+ let(:user_ids) { [member.id.to_s, user_invited_by_id.id.to_s] }
+
+ it 'successfully creates members' do
+ expect(execute_service[:status]).to eq(:success)
+ expect(source.users).to include(member, user_invited_by_id)
+ expect(OnboardingProgress.completed?(source.namespace, :user_added)).to be(true)
+ end
+ end
+
context 'when executing on a group' do
let_it_be(:source) { create(:group) }
@@ -191,6 +222,15 @@ RSpec.describe Members::CreateService, :aggregate_failures, :clean_gitlab_redis_
)
end
+ context 'when it is an invite by email passed to user_ids' do
+ let(:user_ids) { 'email@example.org' }
+
+ it 'does not create task issues' do
+ expect(TasksToBeDone::CreateWorker).not_to receive(:perform_async)
+ execute_service
+ end
+ end
+
context 'when passing many user ids' do
before do
stub_licensed_features(multiple_issue_assignees: false)
diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb
index 8ceb9979f33..ab740138a8b 100644
--- a/spec/services/members/invite_service_spec.rb
+++ b/spec/services/members/invite_service_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
let_it_be(:project, reload: true) { create(:project) }
let_it_be(:user) { project.first_owner }
let_it_be(:project_user) { create(:user) }
+ let_it_be(:user_invited_by_id) { create(:user) }
let_it_be(:namespace) { project.namespace }
let(:params) { {} }
@@ -41,148 +42,422 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
end
end
- context 'when email is not a valid email' do
- let(:params) { { email: '_bogus_' } }
+ context 'when invites are passed as array' do
+ context 'with emails' do
+ let(:params) { { email: %w[email@example.org email2@example.org] } }
- it 'returns an error' do
- expect_not_to_create_members
- expect(result[:message]['_bogus_']).to eq("Invite email is invalid")
+ it 'successfully creates members' do
+ expect_to_create_members(count: 2)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with user_ids as integers' do
+ let(:params) { { user_ids: [project_user.id, user_invited_by_id.id] } }
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 2)
+ expect(result[:status]).to eq(:success)
+ end
end
- it_behaves_like 'does not record an onboarding progress action'
+ context 'with user_ids as strings' do
+ let(:params) { { user_ids: [project_user.id.to_s, user_invited_by_id.id.to_s] } }
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 2)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with a mixture of emails and user_ids' do
+ let(:params) do
+ { user_ids: [project_user.id, user_invited_by_id.id], email: %w[email@example.org email2@example.org] }
+ end
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 4)
+ expect(result[:status]).to eq(:success)
+ end
+ end
end
- context 'when emails are passed as an array' do
- let(:params) { { email: %w[email@example.org email2@example.org] } }
+ context 'with multiple invites passed as strings' do
+ context 'with emails' do
+ let(:params) { { email: 'email@example.org,email2@example.org' } }
- it 'successfully creates members' do
- expect_to_create_members(count: 2)
- expect(result[:status]).to eq(:success)
+ it 'successfully creates members' do
+ expect_to_create_members(count: 2)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with user_ids' do
+ let(:params) { { user_ids: "#{project_user.id},#{user_invited_by_id.id}" } }
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 2)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with a mixture of emails and user_ids' do
+ let(:params) do
+ { user_ids: "#{project_user.id},#{user_invited_by_id.id}", email: 'email@example.org,email2@example.org' }
+ end
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 4)
+ expect(result[:status]).to eq(:success)
+ end
end
end
- context 'when emails are passed as an empty string' do
- let(:params) { { email: '' } }
+ context 'when invites formats are mixed' do
+ context 'when user_ids is an array and emails is a string' do
+ let(:params) do
+ { user_ids: [project_user.id, user_invited_by_id.id], email: 'email@example.org,email2@example.org' }
+ end
+
+ it 'successfully creates members' do
+ expect_to_create_members(count: 4)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'when user_ids is a string and emails is an array' do
+ let(:params) do
+ { user_ids: "#{project_user.id},#{user_invited_by_id.id}", email: %w[email@example.org email2@example.org] }
+ end
- it 'returns an error' do
- expect_not_to_create_members
- expect(result[:message]).to eq('Emails cannot be blank')
+ it 'successfully creates members' do
+ expect_to_create_members(count: 4)
+ expect(result[:status]).to eq(:success)
+ end
end
end
- context 'when email param is not included' do
- it 'returns an error' do
- expect_not_to_create_members
- expect(result[:message]).to eq('Emails cannot be blank')
+ context 'when invites are passed in different formats' do
+ context 'when emails are passed as an empty string' do
+ let(:params) { { email: '' } }
+
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Invites cannot be blank')
+ end
+ end
+
+ context 'when user_ids are passed as an empty string' do
+ let(:params) { { user_ids: '' } }
+
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Invites cannot be blank')
+ end
+ end
+
+ context 'when user_ids and emails are both passed as empty strings' do
+ let(:params) { { user_ids: '', email: '' } }
+
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Invites cannot be blank')
+ end
+ end
+
+ context 'when user_id is passed as an integer' do
+ let(:params) { { user_ids: project_user.id } }
+
+ it 'successfully creates member' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'when invite params are not included' do
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Invites cannot be blank')
+ end
end
end
context 'when email is not a valid email format' do
- let(:params) { { email: '_bogus_' } }
+ context 'with singular email' do
+ let(:params) { { email: '_bogus_' } }
- it 'returns an error' do
- expect { result }.not_to change(ProjectMember, :count)
- expect(result[:status]).to eq(:error)
- expect(result[:message][params[:email]]).to eq("Invite email is invalid")
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:status]).to eq(:error)
+ expect(result[:message][params[:email]]).to eq("Invite email is invalid")
+ end
+
+ it_behaves_like 'does not record an onboarding progress action'
+ end
+
+ context 'with user_id and singular invalid email' do
+ let(:params) { { user_ids: project_user.id, email: '_bogus_' } }
+
+ it 'has partial success' do
+ expect_to_create_members(count: 1)
+ expect(project.users).to include project_user
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message][params[:email]]).to eq("Invite email is invalid")
+ end
end
end
- context 'when duplicate email addresses are passed' do
- let(:params) { { email: 'email@example.org,email@example.org' } }
+ context 'with duplicate invites' do
+ context 'with duplicate emails' do
+ let(:params) { { email: 'email@example.org,email@example.org' } }
- it 'only creates one member per unique address' do
- expect_to_create_members(count: 1)
- expect(result[:status]).to eq(:success)
+ it 'only creates one member per unique invite' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with duplicate user ids' do
+ let(:params) { { user_ids: "#{project_user.id},#{project_user.id}" } }
+
+ it 'only creates one member per unique invite' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'with duplicate member by adding as user id and email' do
+ let(:params) { { user_ids: project_user.id, email: project_user.email } }
+
+ it 'only creates one member per unique invite' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ end
end
end
- context 'when observing email limits' do
- let_it_be(:emails) { Array(1..101).map { |n| "email#{n}@example.com" } }
+ context 'when observing invite limits' do
+ context 'with emails and in general' do
+ let_it_be(:emails) { Array(1..101).map { |n| "email#{n}@example.com" } }
- context 'when over the allowed default limit of emails' do
- let(:params) { { email: emails } }
+ context 'when over the allowed default limit of emails' do
+ let(:params) { { email: emails } }
- it 'limits the number of emails to 100' do
- expect_not_to_create_members
- expect(result[:message]).to eq('Too many users specified (limit is 100)')
+ it 'limits the number of emails to 100' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Too many users specified (limit is 100)')
+ end
+ end
+
+ context 'when over the allowed custom limit of emails' do
+ let(:params) { { email: 'email@example.org,email2@example.org', limit: 1 } }
+
+ it 'limits the number of emails to the limit supplied' do
+ expect_not_to_create_members
+ expect(result[:message]).to eq('Too many users specified (limit is 1)')
+ end
+ end
+
+ context 'when limit allowed is disabled via limit param' do
+ let(:params) { { email: emails, limit: -1 } }
+
+ it 'does not limit number of emails' do
+ expect_to_create_members(count: 101)
+ expect(result[:status]).to eq(:success)
+ end
end
end
- context 'when over the allowed custom limit of emails' do
- let(:params) { { email: 'email@example.org,email2@example.org', limit: 1 } }
+ context 'with user_ids' do
+ let(:user_ids) { 1.upto(101).to_a.join(',') }
+ let(:params) { { user_ids: user_ids } }
- it 'limits the number of emails to the limit supplied' do
+ it 'limits the number of users to 100' do
expect_not_to_create_members
- expect(result[:message]).to eq('Too many users specified (limit is 1)')
+ expect(result[:message]).to eq('Too many users specified (limit is 100)')
end
end
+ end
- context 'when limit allowed is disabled via limit param' do
- let(:params) { { email: emails, limit: -1 } }
+ context 'with an existing user' do
+ context 'with email' do
+ let(:params) { { email: project_user.email } }
- it 'does not limit number of emails' do
- expect_to_create_members(count: 101)
+ it 'adds an existing user to members' do
+ expect_to_create_members(count: 1)
expect(result[:status]).to eq(:success)
+ expect(project.users).to include project_user
end
end
- end
- context 'when email belongs to an existing user' do
- let(:params) { { email: project_user.email } }
+ context 'with user_id' do
+ let(:params) { { user_ids: project_user.id } }
- it 'adds an existing user to members' do
- expect_to_create_members(count: 1)
- expect(result[:status]).to eq(:success)
- expect(project.users).to include project_user
+ it_behaves_like 'records an onboarding progress action', :user_added
+
+ it 'adds an existing user to members' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:success)
+ expect(project.users).to include project_user
+ end
+
+ context 'when assigning tasks to be done' do
+ let(:params) do
+ { user_ids: project_user.id, tasks_to_be_done: %w(ci code), tasks_project_id: project.id }
+ end
+
+ it 'creates 2 task issues', :aggregate_failures do
+ expect(TasksToBeDone::CreateWorker)
+ .to receive(:perform_async)
+ .with(anything, user.id, [project_user.id])
+ .once
+ .and_call_original
+ expect { result }.to change { project.issues.count }.by(2)
+
+ expect(project.issues).to all have_attributes(project: project, author: user)
+ end
+ end
end
end
context 'when access level is not valid' do
- let(:params) { { email: project_user.email, access_level: -1 } }
+ context 'with email' do
+ let(:params) { { email: project_user.email, access_level: -1 } }
- it 'returns an error' do
- expect_not_to_create_members
- expect(result[:message][project_user.email])
- .to eq("Access level is not included in the list")
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message][project_user.email]).to eq("Access level is not included in the list")
+ end
end
- end
- context 'when invite already exists for an included email' do
- let!(:invited_member) { create(:project_member, :invited, project: project) }
- let(:params) { { email: "#{invited_member.invite_email},#{project_user.email}" } }
+ context 'with user_id' do
+ let(:params) { { user_ids: user_invited_by_id.id, access_level: -1 } }
- it 'adds new email and returns an error for the already invited email' do
- expect_to_create_members(count: 1)
- expect(result[:status]).to eq(:error)
- expect(result[:message][invited_member.invite_email])
- .to eq("The member's email address has already been taken")
- expect(project.users).to include project_user
+ it 'returns an error' do
+ expect_not_to_create_members
+ expect(result[:message][user_invited_by_id.username]).to eq("Access level is not included in the list")
+ end
end
- end
- context 'when access request already exists for an included email' do
- let!(:requested_member) { create(:project_member, :access_request, project: project) }
- let(:params) { { email: "#{requested_member.user.email},#{project_user.email}" } }
+ context 'with a mix of user_id and email' do
+ let(:params) { { user_ids: user_invited_by_id.id, email: project_user.email, access_level: -1 } }
- it 'adds new email and returns an error for the already invited email' do
- expect_to_create_members(count: 1)
- expect(result[:status]).to eq(:error)
- expect(result[:message][requested_member.user.email])
- .to eq("User already exists in source")
- expect(project.users).to include project_user
+ it 'returns errors' do
+ expect_not_to_create_members
+ expect(result[:message][project_user.email]).to eq("Access level is not included in the list")
+ expect(result[:message][user_invited_by_id.username]).to eq("Access level is not included in the list")
+ end
end
end
- context 'when email is already a member on the project' do
- let!(:existing_member) { create(:project_member, :guest, project: project) }
- let(:params) { { email: "#{existing_member.user.email},#{project_user.email}" } }
+ context 'when member already exists' do
+ context 'with email' do
+ let!(:invited_member) { create(:project_member, :invited, project: project) }
+ let(:params) { { email: "#{invited_member.invite_email},#{project_user.email}" } }
+
+ it 'adds new email and returns an error for the already invited email' do
+ expect_to_create_members(count: 1)
+ expect(result[:status]).to eq(:error)
+ expect(result[:message][invited_member.invite_email])
+ .to eq("The member's email address has already been taken")
+ expect(project.users).to include project_user
+ end
+ end
- it 'adds new email and returns an error for the already invited email' do
- expect_to_create_members(count: 1)
- expect(result[:status]).to eq(:error)
- expect(result[:message][existing_member.user.email])
- .to eq("User already exists in source")
- expect(project.users).to include project_user
+ context 'when email is already a member with a user on the project' do
+ let!(:existing_member) { create(:project_member, :guest, project: project) }
+ let(:params) { { email: "#{existing_member.user.email}" } }
+
+ it 'returns an error for the already invited email' do
+ expect_not_to_create_members
+ expect(result[:message][existing_member.user.email]).to eq("User already exists in source")
+ end
+
+ context 'when email belongs to an existing user as a secondary email' do
+ let(:secondary_email) { create(:email, email: 'secondary@example.com', user: existing_member.user) }
+ let(:params) { { email: "#{secondary_email.email}" } }
+
+ it 'returns an error for the already invited email' do
+ expect_not_to_create_members
+ expect(result[:message][secondary_email.email]).to eq("User already exists in source")
+ end
+ end
+ end
+
+ context 'with user_id that already exists' do
+ let!(:existing_member) { create(:project_member, project: project, user: project_user) }
+ let(:params) { { user_ids: existing_member.user_id } }
+
+ it 'does not add the member again and is successful' do
+ expect_to_create_members(count: 0)
+ expect(project.users).to include project_user
+ end
+ end
+
+ context 'with user_id that already exists with a lower access_level' do
+ let!(:existing_member) { create(:project_member, :developer, project: project, user: project_user) }
+ let(:params) { { user_ids: existing_member.user_id, access_level: ProjectMember::MAINTAINER } }
+
+ it 'does not add the member again and updates the access_level' do
+ expect_to_create_members(count: 0)
+ expect(project.users).to include project_user
+ expect(existing_member.reset.access_level).to eq ProjectMember::MAINTAINER
+ end
+ end
+
+ context 'with user_id that already exists with a higher access_level' do
+ let!(:existing_member) { create(:project_member, :developer, project: project, user: project_user) }
+ let(:params) { { user_ids: existing_member.user_id, access_level: ProjectMember::GUEST } }
+
+ it 'does not add the member again and updates the access_level' do
+ expect_to_create_members(count: 0)
+ expect(project.users).to include project_user
+ expect(existing_member.reset.access_level).to eq ProjectMember::GUEST
+ end
+ end
+
+ context 'with user_id that already exists in a parent group' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:group_member) { create(:group_member, :developer, source: group, user: project_user) }
+ let_it_be(:project, reload: true) { create(:project, group: group) }
+ let_it_be(:user) { project.creator }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ context 'when access_level is lower than inheriting member' do
+ let(:params) { { user_ids: group_member.user_id, access_level: ProjectMember::GUEST }}
+
+ it 'does not add the member and returns an error' do
+ msg = "Access level should be greater than or equal " \
+ "to Developer inherited membership from group #{group.name}"
+
+ expect_not_to_create_members
+ expect(result[:message][project_user.username]).to eq msg
+ end
+ end
+
+ context 'when access_level is the same as the inheriting member' do
+ let(:params) { { user_ids: group_member.user_id, access_level: ProjectMember::DEVELOPER }}
+
+ it 'adds the member with correct access_level' do
+ expect_to_create_members(count: 1)
+ expect(project.users).to include project_user
+ expect(project.project_members.last.access_level).to eq ProjectMember::DEVELOPER
+ end
+ end
+
+ context 'when access_level is greater than the inheriting member' do
+ let(:params) { { user_ids: group_member.user_id, access_level: ProjectMember::MAINTAINER }}
+
+ it 'adds the member with correct access_level' do
+ expect_to_create_members(count: 1)
+ expect(project.users).to include project_user
+ expect(project.project_members.last.access_level).to eq ProjectMember::MAINTAINER
+ end
+ end
end
end
diff --git a/spec/tasks/dev_rake_spec.rb b/spec/tasks/dev_rake_spec.rb
index 0abed33ec87..af7bd4bdf0b 100644
--- a/spec/tasks/dev_rake_spec.rb
+++ b/spec/tasks/dev_rake_spec.rb
@@ -40,6 +40,58 @@ RSpec.describe 'dev rake tasks' do
end
end
+ describe 'terminate_all_connections' do
+ let(:connections) do
+ Gitlab::Database.database_base_models.values.filter_map do |model|
+ model.connection if Gitlab::Database.db_config_share_with(model.connection_db_config).nil?
+ end
+ end
+
+ def expect_connections_to_be_terminated
+ expect(Gitlab::Database::EachDatabase).to receive(:each_database_connection)
+ .with(include_shared: false)
+ .and_call_original
+
+ expect(connections).to all(receive(:execute).with(/SELECT pg_terminate_backend/))
+ end
+
+ def expect_connections_not_to_be_terminated
+ connections.each do |connection|
+ expect(connection).not_to receive(:execute)
+ end
+ end
+
+ subject(:terminate_task) { run_rake_task('dev:terminate_all_connections') }
+
+ it 'terminates all connections' do
+ expect_connections_to_be_terminated
+
+ terminate_task
+ end
+
+ context 'when in the production environment' do
+ it 'does not terminate connections' do
+ expect(Rails.env).to receive(:production?).and_return(true)
+ expect_connections_not_to_be_terminated
+
+ terminate_task
+ end
+ end
+
+ context 'when a database is not found' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it 'continues to next connection' do
+ expect(connections.first).to receive(:execute).and_raise(ActiveRecord::NoDatabaseError)
+ expect(connections.second).to receive(:execute).with(/SELECT pg_terminate_backend/)
+
+ terminate_task
+ end
+ end
+ end
+
context 'multiple databases' do
before do
skip_if_multiple_databases_not_setup
@@ -48,6 +100,8 @@ RSpec.describe 'dev rake tasks' do
context 'with a valid database' do
describe 'copy_db:ci' do
before do
+ allow(Rake::Task['dev:terminate_all_connections']).to receive(:invoke)
+
configurations = instance_double(ActiveRecord::DatabaseConfigurations)
allow(ActiveRecord::Base).to receive(:configurations).and_return(configurations)
allow(configurations).to receive(:configs_for).with(env_name: Rails.env, name: 'ci').and_return(ci_configuration)
@@ -63,6 +117,8 @@ RSpec.describe 'dev rake tasks' do
template: ApplicationRecord.connection_db_config.database
)
+ expect(Rake::Task['dev:terminate_all_connections']).to receive(:invoke)
+
run_rake_task('dev:copy_db:ci')
end
diff --git a/spec/tasks/gitlab/setup_rake_spec.rb b/spec/tasks/gitlab/setup_rake_spec.rb
index 6b4dde22dca..c31546fc259 100644
--- a/spec/tasks/gitlab/setup_rake_spec.rb
+++ b/spec/tasks/gitlab/setup_rake_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe 'gitlab:setup namespace rake tasks', :silence_stdout do
before do
Rake.application.rake_require 'active_record/railties/databases'
Rake.application.rake_require 'tasks/seed_fu'
+ Rake.application.rake_require 'tasks/dev'
Rake.application.rake_require 'tasks/gitlab/setup'
end
@@ -22,12 +23,6 @@ RSpec.describe 'gitlab:setup namespace rake tasks', :silence_stdout do
let(:server_service1) { double(:server_service) }
let(:server_service2) { double(:server_service) }
- let(:connections) do
- Gitlab::Database.database_base_models.values.filter_map do |model|
- model.connection if Gitlab::Database.db_config_share_with(model.connection_db_config).nil?
- end
- end
-
before do
allow(Gitlab).to receive_message_chain('config.repositories.storages').and_return(storages)
@@ -102,18 +97,6 @@ RSpec.describe 'gitlab:setup namespace rake tasks', :silence_stdout do
end
end
- context 'when the database is not found when terminating connections' do
- it 'continues setting up the database', :aggregate_failures do
- expect_gitaly_connections_to_be_checked
-
- expect(connections).to all(receive(:execute).and_raise(ActiveRecord::NoDatabaseError))
-
- expect_database_to_be_setup
-
- setup_task
- end
- end
-
def expect_gitaly_connections_to_be_checked
expect(Gitlab::GitalyClient::ServerService).to receive(:new).with('name1').and_return(server_service1)
expect(server_service1).to receive(:info)
@@ -123,17 +106,11 @@ RSpec.describe 'gitlab:setup namespace rake tasks', :silence_stdout do
end
def expect_connections_to_be_terminated
- expect(Gitlab::Database::EachDatabase).to receive(:each_database_connection)
- .with(include_shared: false)
- .and_call_original
-
- expect(connections).to all(receive(:execute).with(/SELECT pg_terminate_backend/))
+ expect(Rake::Task['dev:terminate_all_connections']).to receive(:invoke)
end
def expect_connections_not_to_be_terminated
- connections.each do |connection|
- expect(connection).not_to receive(:execute)
- end
+ expect(Rake::Task['dev:terminate_all_connections']).not_to receive(:invoke)
end
def expect_database_to_be_setup
diff --git a/spec/workers/project_export_worker_spec.rb b/spec/workers/project_export_worker_spec.rb
index 9923d8bde7f..dd0a921059d 100644
--- a/spec/workers/project_export_worker_spec.rb
+++ b/spec/workers/project_export_worker_spec.rb
@@ -4,4 +4,30 @@ require 'spec_helper'
RSpec.describe ProjectExportWorker do
it_behaves_like 'export worker'
+
+ context 'exporters duration measuring' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:worker) { described_class.new }
+
+ subject { worker.perform(user.id, project.id) }
+
+ before do
+ project.add_owner(user)
+ end
+
+ it 'logs exporters execution duration' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:version_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:avatar_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:tree_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:uploads_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:repo_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:wiki_repo_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:lfs_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:snippets_repo_saver_duration_s, anything)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:design_repo_saver_duration_s, anything)
+
+ subject
+ end
+ end
end
diff --git a/spec/workers/quality/test_data_cleanup_worker_spec.rb b/spec/workers/quality/test_data_cleanup_worker_spec.rb
deleted file mode 100644
index a17e6e0cb1a..00000000000
--- a/spec/workers/quality/test_data_cleanup_worker_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Quality::TestDataCleanupWorker do
- subject { described_class.new }
-
- shared_examples 'successful deletion' do
- before do
- allow(Gitlab).to receive(:staging?).and_return(true)
- end
-
- it 'removes test groups' do
- expect { subject.perform }.to change(Group, :count).by(-test_group_count)
- end
- end
-
- describe "#perform" do
- context 'with multiple test groups to remove' do
- let(:test_group_count) { 5 }
- let!(:groups_to_remove) { create_list(:group, test_group_count, :test_group) }
- let!(:group_to_keep) { create(:group, path: 'test-group-fulfillment-keep', created_at: 1.day.ago) }
- let!(:non_test_group) { create(:group) }
- let(:non_test_owner_group) { create(:group, path: 'test-group-fulfillment1234', created_at: 4.days.ago) }
-
- before do
- non_test_owner_group.add_owner(create(:user))
- end
-
- it_behaves_like 'successful deletion'
- end
-
- context 'with paid groups' do
- let(:test_group_count) { 1 }
- let!(:paid_group) { create(:group, :test_group) }
-
- before do
- allow(paid_group).to receive(:paid?).and_return(true)
- end
-
- it_behaves_like 'successful deletion'
- end
- end
-end