Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-10 15:09:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-10 15:09:36 +0300
commit948023c9c900344aa1e2f334bcaae5a194873b0d (patch)
tree846c5dbcec70436bca337d970bd11082f91eeb66 /spec
parentf42c4be1c0d5247fac0c059ec41c9a1961485aed (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/components/pajamas/alert_component_spec.rb30
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb94
-rw-r--r--spec/factories/plan_limits.rb6
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb2
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb2
-rw-r--r--spec/frontend/work_items/components/work_item_detail_modal_spec.js12
-rw-r--r--spec/frontend/work_items/components/work_item_state_spec.js9
-rw-r--r--spec/frontend/work_items/components/work_item_title_spec.js31
-rw-r--r--spec/frontend/work_items/pages/work_item_detail_spec.js14
-rw-r--r--spec/frontend/work_items/pages/work_item_root_spec.js1
-rw-r--r--spec/helpers/emails_helper_spec.rb20
-rw-r--r--spec/helpers/form_helper_spec.rb13
-rw-r--r--spec/helpers/notes_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb81
-rw-r--r--spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/trace/archive_spec.rb71
-rw-r--r--spec/lib/gitlab/metrics/sli_spec.rb58
-rw-r--r--spec/lib/gitlab/redis/duplicate_jobs_spec.rb50
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb39
-rw-r--r--spec/lib/gitlab/redis/sidekiq_status_spec.rb68
-rw-r--r--spec/lib/gitlab/sidekiq_status_spec.rb203
-rw-r--r--spec/lib/gitlab/updated_notes_paginator_spec.rb57
-rw-r--r--spec/models/clusters/integrations/prometheus_spec.rb38
-rw-r--r--spec/models/deployment_spec.rb24
-rw-r--r--spec/models/issue_spec.rb32
-rw-r--r--spec/presenters/releases/link_presenter_spec.rb31
-rw-r--r--spec/serializers/integrations/event_entity_spec.rb (renamed from spec/serializers/service_event_entity_spec.rb)12
-rw-r--r--spec/serializers/integrations/field_entity_spec.rb (renamed from spec/serializers/service_field_entity_spec.rb)32
-rw-r--r--spec/support/matchers/exceed_query_limit.rb97
-rw-r--r--spec/workers/clusters/applications/activate_integration_worker_spec.rb (renamed from spec/workers/clusters/applications/activate_service_worker_spec.rb)21
-rw-r--r--spec/workers/clusters/applications/deactivate_integration_worker_spec.rb (renamed from spec/workers/clusters/applications/deactivate_service_worker_spec.rb)31
-rw-r--r--spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb4
-rw-r--r--spec/workers/concerns/limited_capacity/job_tracker_spec.rb2
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb2
35 files changed, 740 insertions, 464 deletions
diff --git a/spec/components/pajamas/alert_component_spec.rb b/spec/components/pajamas/alert_component_spec.rb
index e596f07a15a..db425fb2dce 100644
--- a/spec/components/pajamas/alert_component_spec.rb
+++ b/spec/components/pajamas/alert_component_spec.rb
@@ -138,5 +138,35 @@ RSpec.describe Pajamas::AlertComponent, :aggregate_failures, type: :component do
end
end
end
+
+ context 'with alert_options' do
+ let(:options) { { alert_options: { id: 'test_id', class: 'baz', data: { foo: 'bar' } } } }
+
+ before do
+ render_inline described_class.new(**options)
+ end
+
+ it 'renders the extra options' do
+ expect(rendered_component).to have_css "#test_id.gl-alert.baz[data-foo='bar']"
+ end
+
+ context 'with custom classes or data' do
+ let(:options) do
+ {
+ variant: :danger,
+ alert_class: 'custom',
+ alert_data: { foo: 'bar' },
+ alert_options: {
+ class: 'extra special',
+ data: { foo: 'conflict' }
+ }
+ }
+ end
+
+ it 'doesn\'t conflict with internal alert_class or alert_data' do
+ expect(rendered_component).to have_css ".extra.special.custom.gl-alert.gl-alert-danger[data-foo='bar']"
+ end
+ end
+ end
end
end
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 07874c8a8af..85e5de46afd 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -84,100 +84,6 @@ RSpec.describe Projects::NotesController do
end
end
- context 'for multiple pages of notes', :aggregate_failures do
- # 3 pages worth: 1 normal page, 1 oversized due to clashing updated_at,
- # and a final, short page
- let!(:page_1) { create_list(:note, 2, noteable: issue, project: project, updated_at: 3.days.ago) }
- let!(:page_2) { create_list(:note, 3, noteable: issue, project: project, updated_at: 2.days.ago) }
- let!(:page_3) { create_list(:note, 2, noteable: issue, project: project, updated_at: 1.day.ago) }
-
- # Include a resource event in the middle page as well
- let!(:resource_event) { create(:resource_state_event, issue: issue, user: user, created_at: 2.days.ago) }
-
- let(:page_1_boundary) { microseconds(page_1.last.updated_at + NotesFinder::FETCH_OVERLAP) }
- let(:page_2_boundary) { microseconds(page_2.last.updated_at + NotesFinder::FETCH_OVERLAP) }
-
- around do |example|
- freeze_time do
- example.run
- end
- end
-
- before do
- stub_const('Gitlab::UpdatedNotesPaginator::LIMIT', 2)
- end
-
- context 'feature flag enabled' do
- before do
- stub_feature_flags(paginated_notes: true)
- end
-
- it 'returns the first page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_1.count)
- expect(json_response['more']).to be_truthy
- expect(json_response['last_fetched_at']).to eq(page_1_boundary)
- expect(response.headers['Poll-Interval'].to_i).to eq(1)
- end
-
- it 'returns the second page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = page_1_boundary
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_2.count + 1) # resource event
- expect(json_response['more']).to be_truthy
- expect(json_response['last_fetched_at']).to eq(page_2_boundary)
- expect(response.headers['Poll-Interval'].to_i).to eq(1)
- end
-
- it 'returns the final page of notes' do
- expect(Gitlab::EtagCaching::Middleware).to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = page_2_boundary
-
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq(page_3.count)
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- expect(response.headers['Poll-Interval'].to_i).to be > 1
- end
-
- it 'returns an empty page of notes' do
- expect(Gitlab::EtagCaching::Middleware).not_to receive(:skip!)
-
- request.headers['X-Last-Fetched-At'] = microseconds(Time.zone.now)
-
- get :index, params: request_params
-
- expect(json_response['notes']).to be_empty
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- expect(response.headers['Poll-Interval'].to_i).to be > 1
- end
- end
-
- context 'feature flag disabled' do
- before do
- stub_feature_flags(paginated_notes: false)
- end
-
- it 'returns all notes' do
- get :index, params: request_params
-
- expect(json_response['notes'].count).to eq((page_1 + page_2 + page_3).size + 1)
- expect(json_response['more']).to be_falsy
- expect(json_response['last_fetched_at']).to eq(microseconds(Time.zone.now))
- end
- end
- end
-
context 'for a discussion note' do
let(:project) { create(:project, :repository) }
let!(:note) { create(:discussion_note_on_merge_request, project: project) }
diff --git a/spec/factories/plan_limits.rb b/spec/factories/plan_limits.rb
index ad10629af05..1e4f70cd925 100644
--- a/spec/factories/plan_limits.rb
+++ b/spec/factories/plan_limits.rb
@@ -6,8 +6,10 @@ FactoryBot.define do
dast_profile_schedules { 50 }
- trait :default_plan do
- plan factory: :default_plan
+ Plan.all_plans.each do |plan|
+ trait :"#{plan}_plan" do
+ plan factory: :"#{plan}_plan"
+ end
end
trait :with_package_file_sizes do
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index 9b54d95be6b..9e59ba034d2 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -13,8 +13,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
end
before do
- stub_feature_flags(paginated_notes: false)
-
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 20bf1a2939c..f77a42ee506 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -26,8 +26,6 @@ RSpec.describe 'User comments on a diff', :js do
let(:user) { create(:user) }
before do
- stub_feature_flags(paginated_notes: false)
-
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/frontend/work_items/components/work_item_detail_modal_spec.js b/spec/frontend/work_items/components/work_item_detail_modal_spec.js
index aaabdbc82d9..d55ba318e46 100644
--- a/spec/frontend/work_items/components/work_item_detail_modal_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_modal_spec.js
@@ -29,7 +29,7 @@ describe('WorkItemDetailModal component', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findWorkItemDetail = () => wrapper.findComponent(WorkItemDetail);
- const createComponent = ({ workItemId = '1', error = false } = {}) => {
+ const createComponent = ({ workItemId = '1', issueGid = '2', error = false } = {}) => {
const apolloProvider = createMockApollo([
[
deleteWorkItemFromTaskMutation,
@@ -46,7 +46,7 @@ describe('WorkItemDetailModal component', () => {
wrapper = shallowMount(WorkItemDetailModal, {
apolloProvider,
- propsData: { workItemId },
+ propsData: { workItemId, issueGid },
data() {
return {
error,
@@ -67,6 +67,7 @@ describe('WorkItemDetailModal component', () => {
expect(findWorkItemDetail().props()).toEqual({
workItemId: '1',
+ workItemParentId: '2',
});
});
@@ -97,13 +98,6 @@ describe('WorkItemDetailModal component', () => {
expect(wrapper.emitted('close')).toBeTruthy();
});
- it('emits `workItemUpdated` event on updating work item', () => {
- createComponent();
- findWorkItemDetail().vm.$emit('workItemUpdated');
-
- expect(wrapper.emitted('workItemUpdated')).toBeTruthy();
- });
-
describe('delete work item', () => {
it('emits workItemDeleted and closes modal', async () => {
createComponent();
diff --git a/spec/frontend/work_items/components/work_item_state_spec.js b/spec/frontend/work_items/components/work_item_state_spec.js
index 0e4b73933b1..b379d1fc846 100644
--- a/spec/frontend/work_items/components/work_item_state_spec.js
+++ b/spec/frontend/work_items/components/work_item_state_spec.js
@@ -82,15 +82,6 @@ describe('WorkItemState component', () => {
});
});
- it('emits updated event', async () => {
- createComponent();
-
- findItemState().vm.$emit('changed', STATE_CLOSED);
- await waitForPromises();
-
- expect(wrapper.emitted('updated')).toEqual([[]]);
- });
-
it('emits an error message when the mutation was unsuccessful', async () => {
createComponent({ mutationHandler: jest.fn().mockRejectedValue('Error!') });
diff --git a/spec/frontend/work_items/components/work_item_title_spec.js b/spec/frontend/work_items/components/work_item_title_spec.js
index 168a742090b..a48449bb636 100644
--- a/spec/frontend/work_items/components/work_item_title_spec.js
+++ b/spec/frontend/work_items/components/work_item_title_spec.js
@@ -8,6 +8,7 @@ import ItemTitle from '~/work_items/components/item_title.vue';
import WorkItemTitle from '~/work_items/components/work_item_title.vue';
import { i18n, TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
+import updateWorkItemTaskMutation from '~/work_items/graphql/update_work_item_task.mutation.graphql';
import { updateWorkItemMutationResponse, workItemQueryResponse } from '../mock_data';
describe('WorkItemTitle component', () => {
@@ -19,14 +20,18 @@ describe('WorkItemTitle component', () => {
const findItemTitle = () => wrapper.findComponent(ItemTitle);
- const createComponent = ({ mutationHandler = mutationSuccessHandler } = {}) => {
+ const createComponent = ({ workItemParentId, mutationHandler = mutationSuccessHandler } = {}) => {
const { id, title, workItemType } = workItemQueryResponse.data.workItem;
wrapper = shallowMount(WorkItemTitle, {
- apolloProvider: createMockApollo([[updateWorkItemMutation, mutationHandler]]),
+ apolloProvider: createMockApollo([
+ [updateWorkItemMutation, mutationHandler],
+ [updateWorkItemTaskMutation, mutationHandler],
+ ]),
propsData: {
workItemId: id,
workItemTitle: title,
workItemType: workItemType.name,
+ workItemParentId,
},
});
};
@@ -57,13 +62,25 @@ describe('WorkItemTitle component', () => {
});
});
- it('emits updated event', async () => {
- createComponent();
+ it('calls WorkItemTaskUpdate if passed workItemParentId prop', () => {
+ const title = 'new title!';
+ const workItemParentId = '1234';
- findItemTitle().vm.$emit('title-changed', 'new title');
- await waitForPromises();
+ createComponent({
+ workItemParentId,
+ });
- expect(wrapper.emitted('updated')).toEqual([[]]);
+ findItemTitle().vm.$emit('title-changed', title);
+
+ expect(mutationSuccessHandler).toHaveBeenCalledWith({
+ input: {
+ id: workItemParentId,
+ taskData: {
+ id: workItemQueryResponse.data.workItem.id,
+ title,
+ },
+ },
+ });
});
it('does not call a mutation when the title has not changed', () => {
diff --git a/spec/frontend/work_items/pages/work_item_detail_spec.js b/spec/frontend/work_items/pages/work_item_detail_spec.js
index 33cf2636dd5..b9724034cb4 100644
--- a/spec/frontend/work_items/pages/work_item_detail_spec.js
+++ b/spec/frontend/work_items/pages/work_item_detail_spec.js
@@ -141,20 +141,6 @@ describe('WorkItemDetail component', () => {
});
});
- it('emits workItemUpdated event when fields updated', async () => {
- createComponent();
-
- await waitForPromises();
-
- findWorkItemState().vm.$emit('updated');
-
- expect(wrapper.emitted('workItemUpdated')).toEqual([[]]);
-
- findWorkItemTitle().vm.$emit('updated');
-
- expect(wrapper.emitted('workItemUpdated')).toEqual([[], []]);
- });
-
describe('when work_items_mvc_2 feature flag is enabled', () => {
it('renders assignees component when assignees widget is returned from the API', async () => {
createComponent({
diff --git a/spec/frontend/work_items/pages/work_item_root_spec.js b/spec/frontend/work_items/pages/work_item_root_spec.js
index 85096392e84..61af6f316da 100644
--- a/spec/frontend/work_items/pages/work_item_root_spec.js
+++ b/spec/frontend/work_items/pages/work_item_root_spec.js
@@ -52,6 +52,7 @@ describe('Work items root component', () => {
expect(findWorkItemDetail().props()).toEqual({
workItemId: 'gid://gitlab/WorkItem/1',
+ workItemParentId: null,
});
});
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index 969ef6cae7f..1294bf0ebaf 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -227,13 +227,29 @@ RSpec.describe EmailsHelper do
describe '#header_logo' do
context 'there is a brand item with a logo' do
- it 'returns the brand header logo' do
- appearance = create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png')
+ let_it_be(:appearance) { create(:appearance) }
+
+ let(:logo_path) { 'spec/fixtures/dk.png' }
+ before do
+ appearance.update!(header_logo: fixture_file_upload(logo_path))
+ end
+
+ it 'returns the brand header logo' do
expect(header_logo).to eq(
%{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" />}
)
end
+
+ context 'that is a SVG file' do
+ let(:logo_path) { 'spec/fixtures/logo_sample.svg' }
+
+ it 'returns the default header logo' do
+ expect(header_logo).to match(
+ %r{<img alt="GitLab" src="/images/mailers/gitlab_logo\.(?:gif|png)" width="\d+" height="\d+" />}
+ )
+ end
+ end
end
context 'there is a brand item without a logo' do
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
index 7d5ecbf7a57..25dfa2251c3 100644
--- a/spec/helpers/form_helper_spec.rb
+++ b/spec/helpers/form_helper_spec.rb
@@ -10,11 +10,16 @@ RSpec.describe FormHelper do
expect(helper.form_errors(model)).to be_nil
end
- it 'renders an alert div' do
+ it 'renders an appropriately styled alert div' do
model = double(errors: errors_stub('Error 1'))
- expect(helper.form_errors(model))
+ expect(helper.form_errors(model, pajamas_alert: false))
.to include('<div class="alert alert-danger" id="error_explanation">')
+
+ expect(helper.form_errors(model, pajamas_alert: true))
+ .to include(
+ '<div class="gl-alert gl-alert-danger gl-alert-not-dismissible gl-mb-5" id="error_explanation" role="alert">'
+ )
end
it 'contains a summary message' do
@@ -22,9 +27,9 @@ RSpec.describe FormHelper do
multi_errors = double(errors: errors_stub('A', 'B', 'C'))
expect(helper.form_errors(single_error))
- .to include('<h4>The form contains the following error:')
+ .to include('The form contains the following error:')
expect(helper.form_errors(multi_errors))
- .to include('<h4>The form contains the following errors:')
+ .to include('The form contains the following errors:')
end
it 'renders each message' do
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 913a38d353f..68a6b6293c8 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -329,10 +329,6 @@ RSpec.describe NotesHelper do
allow(helper).to receive(:current_user).and_return(guest)
end
- it 'sets last_fetched_at to 0 when start_at_zero is true' do
- expect(helper.notes_data(issue, true)[:lastFetchedAt]).to eq(0)
- end
-
it 'includes the current notes filter for the user' do
guest.set_notes_filter(UserPreference::NOTES_FILTERS[:only_comments], issue)
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb
new file mode 100644
index 00000000000..3ed4a9f263f
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule/changes_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule::Changes do
+ let(:factory) do
+ Gitlab::Config::Entry::Factory.new(described_class)
+ .value(config)
+ end
+
+ subject(:entry) { factory.create! }
+
+ before do
+ entry.compose!
+ end
+
+ describe '.new' do
+ context 'when using a string array' do
+ let(:config) { %w[app/ lib/ spec/ other/* paths/**/*.rb] }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when using an integer array' do
+ let(:config) { [1, 2] }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns errors' do
+ expect(entry.errors).to include(/changes config should be an array of strings/)
+ end
+ end
+
+ context 'when using a string' do
+ let(:config) { 'a regular string' }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports an error about invalid policy' do
+ expect(entry.errors).to include(/should be an array of strings/)
+ end
+ end
+
+ context 'when using a long array' do
+ let(:config) { ['app/'] * 51 }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns errors' do
+ expect(entry.errors).to include(/has too many entries \(maximum 50\)/)
+ end
+ end
+
+ context 'when clause is empty' do
+ let(:config) {}
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when policy strategy does not match' do
+ let(:config) { 'string strategy' }
+
+ it { is_expected.not_to be_valid }
+
+ it 'returns information about errors' do
+ expect(entry.errors)
+ .to include(/should be an array of strings/)
+ end
+ end
+ end
+
+ describe '#value' do
+ subject(:value) { entry.value }
+
+ context 'when using a string array' do
+ let(:config) { %w[app/ lib/ spec/ other/* paths/**/*.rb] }
+
+ it { is_expected.to eq(config) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
index 86270788431..89d349efe8f 100644
--- a/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/rules/rule_spec.rb
@@ -18,6 +18,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
let(:entry) { factory.create! }
+ before do
+ entry.compose!
+ end
+
describe '.new' do
subject { entry }
@@ -121,7 +125,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.not_to be_valid }
it 'returns errors' do
- expect(subject.errors).to include(/changes should be an array of strings/)
+ expect(subject.errors).to include(/changes config should be an array of strings/)
end
end
@@ -131,7 +135,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
it { is_expected.not_to be_valid }
it 'returns errors' do
- expect(subject.errors).to include(/changes is too long \(maximum is 50 characters\)/)
+ expect(subject.errors).to include(/changes config has too many entries \(maximum 50\)/)
end
end
@@ -434,6 +438,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules::Rule do
end
describe '.default' do
+ let(:config) {}
+
it 'does not have default value' do
expect(described_class.default).to be_nil
end
diff --git a/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb
index 5b0917c5c6f..8f727749ee2 100644
--- a/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb
@@ -4,9 +4,8 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Quota::Deployments do
let_it_be_with_refind(:namespace) { create(:namespace) }
- let_it_be_with_reload(:default_plan) { create(:default_plan) }
let_it_be_with_reload(:project) { create(:project, :repository, namespace: namespace) }
- let_it_be(:plan_limits) { create(:plan_limits, plan: default_plan) }
+ let_it_be(:plan_limits) { create(:plan_limits, :default_plan) }
let(:pipeline) { build_stubbed(:ci_pipeline, project: project) }
diff --git a/spec/lib/gitlab/ci/trace/archive_spec.rb b/spec/lib/gitlab/ci/trace/archive_spec.rb
index 5e965f94347..3ae0e5d1f0e 100644
--- a/spec/lib/gitlab/ci/trace/archive_spec.rb
+++ b/spec/lib/gitlab/ci/trace/archive_spec.rb
@@ -29,35 +29,59 @@ RSpec.describe Gitlab::Ci::Trace::Archive do
let(:stream) { StringIO.new(trace, 'rb') }
let(:src_checksum) { Digest::MD5.hexdigest(trace) }
- context 'when the object store is disabled' do
- before do
- stub_artifacts_object_storage(enabled: false)
+ shared_examples 'valid' do
+ it 'does not count as invalid' do
+ subject.execute!(stream)
+
+ expect(metrics)
+ .not_to have_received(:increment_error_counter)
+ .with(error_reason: :archive_invalid_checksum)
end
+ end
- it 'skips validation' do
+ shared_examples 'local checksum only' do
+ it 'generates only local checksum' do
subject.execute!(stream)
+
expect(trace_metadata.checksum).to eq(src_checksum)
expect(trace_metadata.remote_checksum).to be_nil
- expect(metrics)
- .not_to have_received(:increment_error_counter)
- .with(error_reason: :archive_invalid_checksum)
end
end
- context 'with background_upload enabled' do
+ shared_examples 'skips validations' do
+ it_behaves_like 'valid'
+ it_behaves_like 'local checksum only'
+ end
+
+ shared_context 'with FIPS' do
+ context 'with FIPS enabled', :fips_mode do
+ it_behaves_like 'valid'
+
+ it 'does not generate md5 checksums' do
+ subject.execute!(stream)
+
+ expect(trace_metadata.checksum).to be_nil
+ expect(trace_metadata.remote_checksum).to be_nil
+ end
+ end
+ end
+
+ context 'when the object store is disabled' do
before do
- stub_artifacts_object_storage(background_upload: true)
+ stub_artifacts_object_storage(enabled: false)
end
- it 'skips validation' do
- subject.execute!(stream)
+ it_behaves_like 'skips validations'
+ include_context 'with FIPS'
+ end
- expect(trace_metadata.checksum).to eq(src_checksum)
- expect(trace_metadata.remote_checksum).to be_nil
- expect(metrics)
- .not_to have_received(:increment_error_counter)
- .with(error_reason: :archive_invalid_checksum)
+ context 'with background_upload enabled' do
+ before do
+ stub_artifacts_object_storage(background_upload: true)
end
+
+ it_behaves_like 'skips validations'
+ include_context 'with FIPS'
end
context 'with direct_upload enabled' do
@@ -65,27 +89,26 @@ RSpec.describe Gitlab::Ci::Trace::Archive do
stub_artifacts_object_storage(direct_upload: true)
end
- it 'validates the archived trace' do
+ it_behaves_like 'valid'
+
+ it 'checksums match' do
subject.execute!(stream)
expect(trace_metadata.checksum).to eq(src_checksum)
expect(trace_metadata.remote_checksum).to eq(src_checksum)
- expect(metrics)
- .not_to have_received(:increment_error_counter)
- .with(error_reason: :archive_invalid_checksum)
end
context 'when the checksum does not match' do
let(:invalid_remote_checksum) { SecureRandom.hex }
before do
- expect(::Gitlab::Ci::Trace::RemoteChecksum)
+ allow(::Gitlab::Ci::Trace::RemoteChecksum)
.to receive(:new)
.with(an_instance_of(Ci::JobArtifact))
.and_return(double(md5_checksum: invalid_remote_checksum))
end
- it 'validates the archived trace' do
+ it 'counts as invalid' do
subject.execute!(stream)
expect(trace_metadata.checksum).to eq(src_checksum)
@@ -94,7 +117,11 @@ RSpec.describe Gitlab::Ci::Trace::Archive do
.to have_received(:increment_error_counter)
.with(error_reason: :archive_invalid_checksum)
end
+
+ include_context 'with FIPS'
end
+
+ include_context 'with FIPS'
end
end
end
diff --git a/spec/lib/gitlab/metrics/sli_spec.rb b/spec/lib/gitlab/metrics/sli_spec.rb
index 9b776d6738d..102ea442b3a 100644
--- a/spec/lib/gitlab/metrics/sli_spec.rb
+++ b/spec/lib/gitlab/metrics/sli_spec.rb
@@ -17,13 +17,13 @@ RSpec.describe Gitlab::Metrics::Sli do
it 'allows different SLIs to be defined on each subclass' do
apdex_counters = [
- fake_total_counter('foo', 'apdex'),
- fake_numerator_counter('foo', 'apdex', 'success')
+ fake_total_counter('foo_apdex'),
+ fake_numerator_counter('foo_apdex', 'success')
]
error_rate_counters = [
- fake_total_counter('foo', 'error_rate'),
- fake_numerator_counter('foo', 'error_rate', 'error')
+ fake_total_counter('foo'),
+ fake_numerator_counter('foo', 'error')
]
apdex = described_class::Apdex.initialize_sli(:foo, [{ hello: :world }])
@@ -40,13 +40,17 @@ RSpec.describe Gitlab::Metrics::Sli do
end
subclasses = {
- Gitlab::Metrics::Sli::Apdex => :success,
- Gitlab::Metrics::Sli::ErrorRate => :error
+ Gitlab::Metrics::Sli::Apdex => {
+ suffix: '_apdex',
+ numerator: :success
+ },
+ Gitlab::Metrics::Sli::ErrorRate => {
+ suffix: '',
+ numerator: :error
+ }
}
- subclasses.each do |subclass, numerator_type|
- subclass_type = subclass.to_s.demodulize.underscore
-
+ subclasses.each do |subclass, subclass_info|
describe subclass do
describe 'Class methods' do
before do
@@ -73,8 +77,8 @@ RSpec.describe Gitlab::Metrics::Sli do
describe '.initialize_sli' do
it 'returns and stores a new initialized SLI' do
counters = [
- fake_total_counter(:bar, subclass_type),
- fake_numerator_counter(:bar, subclass_type, numerator_type)
+ fake_total_counter("bar#{subclass_info[:suffix]}"),
+ fake_numerator_counter("bar#{subclass_info[:suffix]}", subclass_info[:numerator])
]
sli = described_class.initialize_sli(:bar, [{ hello: :world }])
@@ -86,8 +90,8 @@ RSpec.describe Gitlab::Metrics::Sli do
it 'does not change labels for an already-initialized SLI' do
counters = [
- fake_total_counter(:bar, subclass_type),
- fake_numerator_counter(:bar, subclass_type, numerator_type)
+ fake_total_counter("bar#{subclass_info[:suffix]}"),
+ fake_numerator_counter("bar#{subclass_info[:suffix]}", subclass_info[:numerator])
]
sli = described_class.initialize_sli(:bar, [{ hello: :world }])
@@ -106,8 +110,8 @@ RSpec.describe Gitlab::Metrics::Sli do
describe '.initialized?' do
before do
- fake_total_counter(:boom, subclass_type)
- fake_numerator_counter(:boom, subclass_type, numerator_type)
+ fake_total_counter("boom#{subclass_info[:suffix]}")
+ fake_numerator_counter("boom#{subclass_info[:suffix]}", subclass_info[:numerator])
end
it 'is true when an SLI was initialized with labels' do
@@ -125,8 +129,8 @@ RSpec.describe Gitlab::Metrics::Sli do
describe '#initialize_counters' do
it 'initializes counters for the passed label combinations' do
counters = [
- fake_total_counter(:hey, subclass_type),
- fake_numerator_counter(:hey, subclass_type, numerator_type)
+ fake_total_counter("hey#{subclass_info[:suffix]}"),
+ fake_numerator_counter("hey#{subclass_info[:suffix]}", subclass_info[:numerator])
]
described_class.new(:hey).initialize_counters([{ foo: 'bar' }, { foo: 'baz' }])
@@ -138,18 +142,18 @@ RSpec.describe Gitlab::Metrics::Sli do
describe "#increment" do
let!(:sli) { described_class.new(:heyo) }
- let!(:total_counter) { fake_total_counter(:heyo, subclass_type) }
- let!(:numerator_counter) { fake_numerator_counter(:heyo, subclass_type, numerator_type) }
+ let!(:total_counter) { fake_total_counter("heyo#{subclass_info[:suffix]}") }
+ let!(:numerator_counter) { fake_numerator_counter("heyo#{subclass_info[:suffix]}", subclass_info[:numerator]) }
- it "increments both counters for labels when #{numerator_type} is true" do
- sli.increment(labels: { hello: "world" }, numerator_type => true)
+ it "increments both counters for labels when #{subclass_info[:numerator]} is true" do
+ sli.increment(labels: { hello: "world" }, subclass_info[:numerator] => true)
expect(total_counter).to have_received(:increment).with({ hello: 'world' })
expect(numerator_counter).to have_received(:increment).with({ hello: 'world' })
end
- it "only increments the total counters for labels when #{numerator_type} is false" do
- sli.increment(labels: { hello: "world" }, numerator_type => false)
+ it "only increments the total counters for labels when #{subclass_info[:numerator]} is false" do
+ sli.increment(labels: { hello: "world" }, subclass_info[:numerator] => false)
expect(total_counter).to have_received(:increment).with({ hello: 'world' })
expect(numerator_counter).not_to have_received(:increment).with({ hello: 'world' })
@@ -168,11 +172,11 @@ RSpec.describe Gitlab::Metrics::Sli do
fake_counter
end
- def fake_total_counter(name, type)
- fake_prometheus_counter("gitlab_sli:#{name}_#{type}:total")
+ def fake_total_counter(name)
+ fake_prometheus_counter("gitlab_sli:#{name}:total")
end
- def fake_numerator_counter(name, type, numerator_name)
- fake_prometheus_counter("gitlab_sli:#{name}_#{type}:#{numerator_name}_total")
+ def fake_numerator_counter(name, numerator_name)
+ fake_prometheus_counter("gitlab_sli:#{name}:#{numerator_name}_total")
end
end
diff --git a/spec/lib/gitlab/redis/duplicate_jobs_spec.rb b/spec/lib/gitlab/redis/duplicate_jobs_spec.rb
index 33f7391a836..53e3d73d17e 100644
--- a/spec/lib/gitlab/redis/duplicate_jobs_spec.rb
+++ b/spec/lib/gitlab/redis/duplicate_jobs_spec.rb
@@ -12,17 +12,11 @@ RSpec.describe Gitlab::Redis::DuplicateJobs do
include_examples "redis_shared_examples"
describe '#pool' do
- let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
- let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
-
subject { described_class.pool }
before do
redis_clear_raw_config!(Gitlab::Redis::SharedState)
redis_clear_raw_config!(Gitlab::Redis::Queues)
-
- allow(Gitlab::Redis::SharedState).to receive(:config_file_name).and_return(config_new_format_host)
- allow(Gitlab::Redis::Queues).to receive(:config_file_name).and_return(config_new_format_socket)
end
after do
@@ -37,14 +31,46 @@ RSpec.describe Gitlab::Redis::DuplicateJobs do
clear_pool
end
- it 'instantiates an instance of MultiStore' do
- subject.with do |redis_instance|
- expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
+ context 'store connection settings' do
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+
+ before do
+ allow(Gitlab::Redis::SharedState).to receive(:config_file_name).and_return(config_new_format_host)
+ allow(Gitlab::Redis::Queues).to receive(:config_file_name).and_return(config_new_format_socket)
+ end
+
+ it 'instantiates an instance of MultiStore' do
+ subject.with do |redis_instance|
+ expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
+
+ expect(redis_instance.primary_store.connection[:id]).to eq("redis://test-host:6379/99")
+ expect(redis_instance.primary_store.connection[:namespace]).to be_nil
+ expect(redis_instance.secondary_store.connection[:id]).to eq("redis:///path/to/redis.sock/0")
+ expect(redis_instance.secondary_store.connection[:namespace]).to eq("resque:gitlab")
+
+ expect(redis_instance.instance_name).to eq('DuplicateJobs')
+ end
+ end
+ end
+
+ # Make sure they current namespace is respected for the secondary store but omitted from the primary
+ context 'key namespaces' do
+ let(:key) { 'key' }
+ let(:value) { '123' }
+
+ it 'writes keys to SharedState with no prefix, and to Queues with the "resque:gitlab:" prefix' do
+ subject.with do |redis_instance|
+ redis_instance.set(key, value)
+ end
- expect(redis_instance.primary_store.connection[:id]).to eq("redis://test-host:6379/99")
- expect(redis_instance.secondary_store.connection[:id]).to eq("redis:///path/to/redis.sock/0")
+ Gitlab::Redis::SharedState.with do |redis_instance|
+ expect(redis_instance.get(key)).to eq(value)
+ end
- expect(redis_instance.instance_name).to eq('DuplicateJobs')
+ Gitlab::Redis::Queues.with do |redis_instance|
+ expect(redis_instance.get("resque:gitlab:#{key}")).to eq(value)
+ end
end
end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 70f28b38082..e127c89c303 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -65,6 +65,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
context 'when primary_store is not a ::Redis instance' do
before do
allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false)
+ allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false)
end
it 'fails with exception' do
@@ -73,9 +74,21 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
end
+ context 'when primary_store is a ::Redis::Namespace instance' do
+ before do
+ allow(primary_store).to receive(:is_a?).with(::Redis).and_return(false)
+ allow(primary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true)
+ end
+
+ it 'fails with exception' do
+ expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error
+ end
+ end
+
context 'when secondary_store is not a ::Redis instance' do
before do
allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false)
+ allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(false)
end
it 'fails with exception' do
@@ -84,6 +97,17 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
end
+ context 'when secondary_store is a ::Redis::Namespace instance' do
+ before do
+ allow(secondary_store).to receive(:is_a?).with(::Redis).and_return(false)
+ allow(secondary_store).to receive(:is_a?).with(::Redis::Namespace).and_return(true)
+ end
+
+ it 'fails with exception' do
+ expect { described_class.new(primary_store, secondary_store, instance_name) }.not_to raise_error
+ end
+ end
+
context 'with READ redis commands' do
let_it_be(:key1) { "redis:{1}:key_a" }
let_it_be(:key2) { "redis:{1}:key_b" }
@@ -145,7 +169,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'logs the ReadFromPrimaryError' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
an_instance_of(Gitlab::Redis::MultiStore::ReadFromPrimaryError),
- hash_including(command_name: name, extra: hash_including(instance_name: instance_name))
+ hash_including(command_name: name, instance_name: instance_name)
)
subject
@@ -222,8 +246,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'logs the exception' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(extra: hash_including(:multi_store_error_message, instance_name: instance_name),
- command_name: name))
+ hash_including(:multi_store_error_message, instance_name: instance_name, command_name: name))
subject
end
@@ -404,7 +427,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'logs the exception and execute on secondary instance', :aggregate_errors do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(extra: hash_including(:multi_store_error_message), command_name: name))
+ hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
expect(secondary_store).to receive(name).with(*expected_args).and_call_original
subject
@@ -525,7 +548,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'logs the exception and execute on secondary instance', :aggregate_errors do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(extra: hash_including(:multi_store_error_message), command_name: name))
+ hash_including(:multi_store_error_message, command_name: name))
expect(secondary_store).to receive(name).and_call_original
subject
@@ -563,7 +586,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'returns the value from the secondary store, logging an error' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
an_instance_of(Gitlab::Redis::MultiStore::PipelinedDiffError),
- hash_including(command_name: name, extra: hash_including(instance_name: instance_name))
+ hash_including(command_name: name, instance_name: instance_name)
).and_call_original
expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
@@ -579,7 +602,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'returns the value from the secondary store, logging an error' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
an_instance_of(Gitlab::Redis::MultiStore::PipelinedDiffError),
- hash_including(command_name: name, extra: hash_including(instance_name: instance_name))
+ hash_including(command_name: name, instance_name: instance_name)
)
expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
@@ -673,7 +696,7 @@ RSpec.describe Gitlab::Redis::MultiStore do
it 'logs MethodMissingError' do
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
an_instance_of(Gitlab::Redis::MultiStore::MethodMissingError),
- hash_including(command_name: :incr, extra: hash_including(instance_name: instance_name))
+ hash_including(command_name: :incr, instance_name: instance_name)
)
subject
diff --git a/spec/lib/gitlab/redis/sidekiq_status_spec.rb b/spec/lib/gitlab/redis/sidekiq_status_spec.rb
new file mode 100644
index 00000000000..f641ea40efd
--- /dev/null
+++ b/spec/lib/gitlab/redis/sidekiq_status_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Redis::SidekiqStatus do
+ # Note: this is a pseudo-store in front of `SharedState`, meant only as a tool
+ # to move away from `Sidekiq.redis` for sidekiq status data. Thus, we use the
+ # same store configuration as the former.
+ let(:instance_specific_config_file) { "config/redis.shared_state.yml" }
+ let(:environment_config_file_name) { "GITLAB_REDIS_SHARED_STATE_CONFIG_FILE" }
+
+ include_examples "redis_shared_examples"
+
+ describe '#pool' do
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+
+ subject { described_class.pool }
+
+ before do
+ redis_clear_raw_config!(Gitlab::Redis::SharedState)
+ redis_clear_raw_config!(Gitlab::Redis::Queues)
+
+ allow(Gitlab::Redis::SharedState).to receive(:config_file_name).and_return(config_new_format_host)
+ allow(Gitlab::Redis::Queues).to receive(:config_file_name).and_return(config_new_format_socket)
+ end
+
+ after do
+ redis_clear_raw_config!(Gitlab::Redis::SharedState)
+ redis_clear_raw_config!(Gitlab::Redis::Queues)
+ end
+
+ around do |example|
+ clear_pool
+ example.run
+ ensure
+ clear_pool
+ end
+
+ it 'instantiates an instance of MultiStore' do
+ subject.with do |redis_instance|
+ expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
+
+ expect(redis_instance.primary_store.connection[:id]).to eq("redis://test-host:6379/99")
+ expect(redis_instance.secondary_store.connection[:id]).to eq("redis:///path/to/redis.sock/0")
+
+ expect(redis_instance.instance_name).to eq('SidekiqStatus')
+ end
+ end
+
+ it_behaves_like 'multi store feature flags', :use_primary_and_secondary_stores_for_sidekiq_status,
+ :use_primary_store_as_default_for_sidekiq_status
+ end
+
+ describe '#raw_config_hash' do
+ it 'has a legacy default URL' do
+ expect(subject).to receive(:fetch_config) { false }
+
+ expect(subject.send(:raw_config_hash)).to eq(url: 'redis://localhost:6382')
+ end
+ end
+
+ describe '#store_name' do
+ it 'returns the name of the SharedState store' do
+ expect(described_class.store_name).to eq('SharedState')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb
index c94deb8e008..027697db7e1 100644
--- a/spec/lib/gitlab/sidekiq_status_spec.rb
+++ b/spec/lib/gitlab/sidekiq_status_spec.rb
@@ -3,138 +3,175 @@
require 'spec_helper'
RSpec.describe Gitlab::SidekiqStatus, :clean_gitlab_redis_queues, :clean_gitlab_redis_shared_state do
- describe '.set' do
- it 'stores the job ID' do
- described_class.set('123')
+ shared_examples 'tracking status in redis' do
+ describe '.set' do
+ it 'stores the job ID' do
+ described_class.set('123')
+
+ key = described_class.key_for('123')
+
+ with_redis do |redis|
+ expect(redis.exists(key)).to eq(true)
+ expect(redis.ttl(key) > 0).to eq(true)
+ expect(redis.get(key)).to eq('1')
+ end
+ end
- key = described_class.key_for('123')
+ it 'allows overriding the expiration time' do
+ described_class.set('123', described_class::DEFAULT_EXPIRATION * 2)
+
+ key = described_class.key_for('123')
- Sidekiq.redis do |redis|
- expect(redis.exists(key)).to eq(true)
- expect(redis.ttl(key) > 0).to eq(true)
- expect(redis.get(key)).to eq('1')
+ with_redis do |redis|
+ expect(redis.exists(key)).to eq(true)
+ expect(redis.ttl(key) > described_class::DEFAULT_EXPIRATION).to eq(true)
+ expect(redis.get(key)).to eq('1')
+ end
end
- end
- it 'allows overriding the expiration time' do
- described_class.set('123', described_class::DEFAULT_EXPIRATION * 2)
+ it 'does not store anything with a nil expiry' do
+ described_class.set('123', nil)
- key = described_class.key_for('123')
+ key = described_class.key_for('123')
- Sidekiq.redis do |redis|
- expect(redis.exists(key)).to eq(true)
- expect(redis.ttl(key) > described_class::DEFAULT_EXPIRATION).to eq(true)
- expect(redis.get(key)).to eq('1')
+ with_redis do |redis|
+ expect(redis.exists(key)).to eq(false)
+ end
end
end
- it 'does not store anything with a nil expiry' do
- described_class.set('123', nil)
+ describe '.unset' do
+ it 'removes the job ID' do
+ described_class.set('123')
+ described_class.unset('123')
- key = described_class.key_for('123')
+ key = described_class.key_for('123')
- Sidekiq.redis do |redis|
- expect(redis.exists(key)).to eq(false)
+ with_redis do |redis|
+ expect(redis.exists(key)).to eq(false)
+ end
end
end
- end
- describe '.unset' do
- it 'removes the job ID' do
- described_class.set('123')
- described_class.unset('123')
+ describe '.all_completed?' do
+ it 'returns true if all jobs have been completed' do
+ expect(described_class.all_completed?(%w(123))).to eq(true)
+ end
- key = described_class.key_for('123')
+ it 'returns false if a job has not yet been completed' do
+ described_class.set('123')
- Sidekiq.redis do |redis|
- expect(redis.exists(key)).to eq(false)
+ expect(described_class.all_completed?(%w(123 456))).to eq(false)
end
end
- end
- describe '.all_completed?' do
- it 'returns true if all jobs have been completed' do
- expect(described_class.all_completed?(%w(123))).to eq(true)
- end
+ describe '.running?' do
+ it 'returns true if job is running' do
+ described_class.set('123')
- it 'returns false if a job has not yet been completed' do
- described_class.set('123')
+ expect(described_class.running?('123')).to be(true)
+ end
- expect(described_class.all_completed?(%w(123 456))).to eq(false)
+ it 'returns false if job is not found' do
+ expect(described_class.running?('123')).to be(false)
+ end
end
- end
- describe '.running?' do
- it 'returns true if job is running' do
- described_class.set('123')
+ describe '.num_running' do
+ it 'returns 0 if all jobs have been completed' do
+ expect(described_class.num_running(%w(123))).to eq(0)
+ end
+
+ it 'returns 2 if two jobs are still running' do
+ described_class.set('123')
+ described_class.set('456')
- expect(described_class.running?('123')).to be(true)
+ expect(described_class.num_running(%w(123 456 789))).to eq(2)
+ end
end
- it 'returns false if job is not found' do
- expect(described_class.running?('123')).to be(false)
+ describe '.num_completed' do
+ it 'returns 1 if all jobs have been completed' do
+ expect(described_class.num_completed(%w(123))).to eq(1)
+ end
+
+ it 'returns 1 if a job has not yet been completed' do
+ described_class.set('123')
+ described_class.set('456')
+
+ expect(described_class.num_completed(%w(123 456 789))).to eq(1)
+ end
end
- end
- describe '.num_running' do
- it 'returns 0 if all jobs have been completed' do
- expect(described_class.num_running(%w(123))).to eq(0)
+ describe '.completed_jids' do
+ it 'returns the completed job' do
+ expect(described_class.completed_jids(%w(123))).to eq(['123'])
+ end
+
+ it 'returns only the jobs completed' do
+ described_class.set('123')
+ described_class.set('456')
+
+ expect(described_class.completed_jids(%w(123 456 789))).to eq(['789'])
+ end
end
- it 'returns 2 if two jobs are still running' do
- described_class.set('123')
- described_class.set('456')
+ describe '.job_status' do
+ it 'returns an array of boolean values' do
+ described_class.set('123')
+ described_class.set('456')
+ described_class.unset('123')
- expect(described_class.num_running(%w(123 456 789))).to eq(2)
+ expect(described_class.job_status(%w(123 456 789))).to eq([false, true, false])
+ end
+
+ it 'handles an empty array' do
+ expect(described_class.job_status([])).to eq([])
+ end
end
end
- describe '.num_completed' do
- it 'returns 1 if all jobs have been completed' do
- expect(described_class.num_completed(%w(123))).to eq(1)
+ context 'with multi-store feature flags turned on' do
+ def with_redis(&block)
+ Gitlab::Redis::SidekiqStatus.with(&block)
end
- it 'returns 1 if a job has not yet been completed' do
- described_class.set('123')
- described_class.set('456')
+ it 'uses Gitlab::Redis::SidekiqStatus.with' do
+ expect(Gitlab::Redis::SidekiqStatus).to receive(:with).and_call_original
+ expect(Sidekiq).not_to receive(:redis)
- expect(described_class.num_completed(%w(123 456 789))).to eq(1)
+ described_class.job_status(%w(123 456 789))
end
- end
- describe '.key_for' do
- it 'returns the key for a job ID' do
- key = described_class.key_for('123')
+ it_behaves_like 'tracking status in redis'
+ end
- expect(key).to be_an_instance_of(String)
- expect(key).to include('123')
+ context 'when both multi-store feature flags are off' do
+ def with_redis(&block)
+ Sidekiq.redis(&block)
end
- end
- describe '.completed_jids' do
- it 'returns the completed job' do
- expect(described_class.completed_jids(%w(123))).to eq(['123'])
+ before do
+ stub_feature_flags(use_primary_and_secondary_stores_for_sidekiq_status: false)
+ stub_feature_flags(use_primary_store_as_default_for_sidekiq_status: false)
end
- it 'returns only the jobs completed' do
- described_class.set('123')
- described_class.set('456')
+ it 'uses Sidekiq.redis' do
+ expect(Sidekiq).to receive(:redis).and_call_original
+ expect(Gitlab::Redis::SidekiqStatus).not_to receive(:with)
- expect(described_class.completed_jids(%w(123 456 789))).to eq(['789'])
+ described_class.job_status(%w(123 456 789))
end
- end
- describe '.job_status' do
- it 'returns an array of boolean values' do
- described_class.set('123')
- described_class.set('456')
- described_class.unset('123')
+ it_behaves_like 'tracking status in redis'
+ end
- expect(described_class.job_status(%w(123 456 789))).to eq([false, true, false])
- end
+ describe '.key_for' do
+ it 'returns the key for a job ID' do
+ key = described_class.key_for('123')
- it 'handles an empty array' do
- expect(described_class.job_status([])).to eq([])
+ expect(key).to be_an_instance_of(String)
+ expect(key).to include('123')
end
end
end
diff --git a/spec/lib/gitlab/updated_notes_paginator_spec.rb b/spec/lib/gitlab/updated_notes_paginator_spec.rb
deleted file mode 100644
index ce6a7719fb4..00000000000
--- a/spec/lib/gitlab/updated_notes_paginator_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::UpdatedNotesPaginator do
- let(:issue) { create(:issue) }
-
- let(:project) { issue.project }
- let(:finder) { NotesFinder.new(user, target: issue, last_fetched_at: last_fetched_at) }
- let(:user) { issue.author }
-
- let!(:page_1) { create_list(:note, 2, noteable: issue, project: project, updated_at: 2.days.ago) }
- let!(:page_2) { [create(:note, noteable: issue, project: project, updated_at: 1.day.ago)] }
-
- let(:page_1_boundary) { page_1.last.updated_at + NotesFinder::FETCH_OVERLAP }
-
- around do |example|
- freeze_time do
- example.run
- end
- end
-
- before do
- stub_const("Gitlab::UpdatedNotesPaginator::LIMIT", 2)
- end
-
- subject(:paginator) { described_class.new(finder.execute, last_fetched_at: last_fetched_at) }
-
- describe 'last_fetched_at: start of time' do
- let(:last_fetched_at) { Time.at(0) }
-
- it 'calculates the first page of notes', :aggregate_failures do
- expect(paginator.notes).to match_array(page_1)
- expect(paginator.metadata).to match(
- more: true,
- last_fetched_at: microseconds(page_1_boundary)
- )
- end
- end
-
- describe 'last_fetched_at: start of final page' do
- let(:last_fetched_at) { page_1_boundary }
-
- it 'calculates a final page', :aggregate_failures do
- expect(paginator.notes).to match_array(page_2)
- expect(paginator.metadata).to match(
- more: false,
- last_fetched_at: microseconds(Time.zone.now)
- )
- end
- end
-
- # Convert a time to an integer number of microseconds
- def microseconds(time)
- (time.to_i * 1_000_000) + time.usec
- end
-end
diff --git a/spec/models/clusters/integrations/prometheus_spec.rb b/spec/models/clusters/integrations/prometheus_spec.rb
index e529c751889..d1e40fffee0 100644
--- a/spec/models/clusters/integrations/prometheus_spec.rb
+++ b/spec/models/clusters/integrations/prometheus_spec.rb
@@ -21,11 +21,24 @@ RSpec.describe Clusters::Integrations::Prometheus do
let(:cluster) { create(:cluster, :with_installed_helm) }
it 'deactivates prometheus_integration' do
- expect(Clusters::Applications::DeactivateServiceWorker)
+ expect(Clusters::Applications::DeactivateIntegrationWorker)
.to receive(:perform_async).with(cluster.id, 'prometheus')
integration.destroy!
end
+
+ context 'when the FF :rename_integrations_workers is disabled' do
+ before do
+ stub_feature_flags(rename_integrations_workers: false)
+ end
+
+ it 'uses the old worker' do
+ expect(Clusters::Applications::DeactivateServiceWorker)
+ .to receive(:perform_async).with(cluster.id, 'prometheus')
+
+ integration.destroy!
+ end
+ end
end
describe 'after_save' do
@@ -38,10 +51,10 @@ RSpec.describe Clusters::Integrations::Prometheus do
it 'does not touch project integrations' do
integration # ensure integration exists before we set the expectations
- expect(Clusters::Applications::DeactivateServiceWorker)
+ expect(Clusters::Applications::DeactivateIntegrationWorker)
.not_to receive(:perform_async)
- expect(Clusters::Applications::ActivateServiceWorker)
+ expect(Clusters::Applications::ActivateIntegrationWorker)
.not_to receive(:perform_async)
integration.update!(enabled: enabled)
@@ -51,19 +64,32 @@ RSpec.describe Clusters::Integrations::Prometheus do
context 'when enabling' do
let(:enabled) { false }
- it 'deactivates prometheus_integration' do
- expect(Clusters::Applications::ActivateServiceWorker)
+ it 'activates prometheus_integration' do
+ expect(Clusters::Applications::ActivateIntegrationWorker)
.to receive(:perform_async).with(cluster.id, 'prometheus')
integration.update!(enabled: true)
end
+
+ context 'when the FF :rename_integrations_workers is disabled' do
+ before do
+ stub_feature_flags(rename_integrations_workers: false)
+ end
+
+ it 'uses the old worker' do
+ expect(Clusters::Applications::ActivateServiceWorker)
+ .to receive(:perform_async).with(cluster.id, 'prometheus')
+
+ integration.update!(enabled: true)
+ end
+ end
end
context 'when disabling' do
let(:enabled) { true }
it 'activates prometheus_integration' do
- expect(Clusters::Applications::DeactivateServiceWorker)
+ expect(Clusters::Applications::DeactivateIntegrationWorker)
.to receive(:perform_async).with(cluster.id, 'prometheus')
integration.update!(enabled: false)
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 28040dd0365..a58d32dfe5d 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -27,41 +27,21 @@ RSpec.describe Deployment do
describe '#manual_actions' do
let(:deployment) { create(:deployment) }
- it 'delegates to environment_manual_actions when deployment_environment_manual_actions ff is enabled' do
- stub_feature_flags(deployment_environment_manual_actions: true)
-
+ it 'delegates to environment_manual_actions' do
expect(deployment.deployable).to receive(:environment_manual_actions).and_call_original
deployment.manual_actions
end
-
- it 'delegates to other_manual_actions when deployment_environment_manual_actions ff is disabled' do
- stub_feature_flags(deployment_environment_manual_actions: false)
-
- expect(deployment.deployable).to receive(:other_manual_actions).and_call_original
-
- deployment.manual_actions
- end
end
describe '#scheduled_actions' do
let(:deployment) { create(:deployment) }
- it 'delegates to environment_scheduled_actions when deployment_environment_manual_actions ff is enabled' do
- stub_feature_flags(deployment_environment_manual_actions: true)
-
+ it 'delegates to environment_scheduled_actions' do
expect(deployment.deployable).to receive(:environment_scheduled_actions).and_call_original
deployment.scheduled_actions
end
-
- it 'delegates to other_scheduled_actions when deployment_environment_manual_actions ff is disabled' do
- stub_feature_flags(deployment_environment_manual_actions: false)
-
- expect(deployment.deployable).to receive(:other_scheduled_actions).and_call_original
-
- deployment.scheduled_actions
- end
end
describe 'modules' do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index d665b92d80f..97c76c58560 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -455,7 +455,7 @@ RSpec.describe Issue do
end
end
- describe '#related_issues' do
+ describe '#related_issues to relate incidents and issues' do
let_it_be(:authorized_project) { create(:project) }
let_it_be(:authorized_project2) { create(:project) }
let_it_be(:unauthorized_project) { create(:project) }
@@ -463,12 +463,14 @@ RSpec.describe Issue do
let_it_be(:authorized_issue_a) { create(:issue, project: authorized_project) }
let_it_be(:authorized_issue_b) { create(:issue, project: authorized_project) }
let_it_be(:authorized_issue_c) { create(:issue, project: authorized_project2) }
+ let_it_be(:authorized_incident_a) { create(:incident, project: authorized_project )}
let_it_be(:unauthorized_issue) { create(:issue, project: unauthorized_project) }
let_it_be(:issue_link_a) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_b) }
let_it_be(:issue_link_b) { create(:issue_link, source: authorized_issue_a, target: unauthorized_issue) }
let_it_be(:issue_link_c) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_c) }
+ let_it_be(:issue_incident_link_a) { create(:issue_link, source: authorized_issue_a, target: authorized_incident_a) }
before_all do
authorized_project.add_developer(user)
@@ -477,7 +479,7 @@ RSpec.describe Issue do
it 'returns only authorized related issues for given user' do
expect(authorized_issue_a.related_issues(user))
- .to contain_exactly(authorized_issue_b, authorized_issue_c)
+ .to contain_exactly(authorized_issue_b, authorized_issue_c, authorized_incident_a)
end
it 'returns issues with valid issue_link_type' do
@@ -507,7 +509,7 @@ RSpec.describe Issue do
expect(Ability).to receive(:allowed?).with(user, :read_cross_project).and_return(false)
expect(authorized_issue_a.related_issues(user))
- .to contain_exactly(authorized_issue_b)
+ .to contain_exactly(authorized_issue_b, authorized_incident_a)
end
end
end
@@ -1581,4 +1583,28 @@ RSpec.describe Issue do
expire_cache
end
end
+
+ describe '#link_reference_pattern' do
+ let(:match_data) { described_class.link_reference_pattern.match(link_reference_url) }
+
+ context 'with issue url' do
+ let(:link_reference_url) { 'http://localhost/namespace/project/-/issues/1' }
+
+ it 'matches with expected attributes' do
+ expect(match_data['namespace']).to eq('namespace')
+ expect(match_data['project']).to eq('project')
+ expect(match_data['issue']).to eq('1')
+ end
+ end
+
+ context 'with incident url' do
+ let(:link_reference_url) { 'http://localhost/namespace1/project1/-/issues/incident/2' }
+
+ it 'matches with expected attributes' do
+ expect(match_data['namespace']).to eq('namespace1')
+ expect(match_data['project']).to eq('project1')
+ expect(match_data['issue']).to eq('2')
+ end
+ end
+ end
end
diff --git a/spec/presenters/releases/link_presenter_spec.rb b/spec/presenters/releases/link_presenter_spec.rb
new file mode 100644
index 00000000000..e52c68ffb38
--- /dev/null
+++ b/spec/presenters/releases/link_presenter_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Releases::LinkPresenter do
+ describe '#direct_asset_url' do
+ let_it_be(:release) { create(:release) }
+
+ let(:link) { build(:release_link, release: release, url: url, filepath: filepath) }
+ let(:url) { 'https://google.com/-/jobs/140463678/artifacts/download' }
+ let(:presenter) { described_class.new(link) }
+
+ subject { presenter.direct_asset_url }
+
+ context 'when filepath is provided' do
+ let(:filepath) { '/bin/bigfile.exe' }
+ let(:expected_url) do
+ "http://localhost/#{release.project.namespace.path}/#{release.project.name}" \
+ "/-/releases/#{release.tag}/downloads/bin/bigfile.exe"
+ end
+
+ it { is_expected.to eq(expected_url) }
+ end
+
+ context 'when filepath is not provided' do
+ let(:filepath) { nil }
+
+ it { is_expected.to eq(url) }
+ end
+ end
+end
diff --git a/spec/serializers/service_event_entity_spec.rb b/spec/serializers/integrations/event_entity_spec.rb
index db82e84fcf8..07281248f5b 100644
--- a/spec/serializers/service_event_entity_spec.rb
+++ b/spec/serializers/integrations/event_entity_spec.rb
@@ -2,17 +2,17 @@
require 'spec_helper'
-RSpec.describe ServiceEventEntity do
- let(:request) { double('request') }
+RSpec.describe Integrations::EventEntity do
+ let(:request) { EntityRequest.new(integration: integration) }
- subject { described_class.new(event, request: request, service: integration).as_json }
+ subject { described_class.new(event, request: request, integration: integration).as_json }
before do
- allow(request).to receive(:service).and_return(integration)
+ allow(request).to receive(:integration).and_return(integration)
end
describe '#as_json' do
- context 'integration without fields' do
+ context 'with integration without fields' do
let(:integration) { create(:emails_on_push_integration, push_events: true) }
let(:event) { 'push' }
@@ -24,7 +24,7 @@ RSpec.describe ServiceEventEntity do
end
end
- context 'integration with fields' do
+ context 'with integration with fields' do
let(:integration) { create(:integrations_slack, note_events: false, note_channel: 'note-channel') }
let(:event) { 'note' }
diff --git a/spec/serializers/service_field_entity_spec.rb b/spec/serializers/integrations/field_entity_spec.rb
index 3a574c522b0..e75dc051f5e 100644
--- a/spec/serializers/service_field_entity_spec.rb
+++ b/spec/serializers/integrations/field_entity_spec.rb
@@ -2,20 +2,20 @@
require 'spec_helper'
-RSpec.describe ServiceFieldEntity do
- let(:request) { double('request') }
+RSpec.describe Integrations::FieldEntity do
+ let(:request) { EntityRequest.new(integration: integration) }
- subject { described_class.new(field, request: request, service: integration).as_json }
+ subject { described_class.new(field, request: request, integration: integration).as_json }
before do
- allow(request).to receive(:service).and_return(integration)
+ allow(request).to receive(:integration).and_return(integration)
end
describe '#as_json' do
- context 'Jira Service' do
+ context 'with Jira integration' do
let(:integration) { create(:jira_integration) }
- context 'field with type text' do
+ context 'with field with type text' do
let(:field) { integration_field('username') }
it 'exposes correct attributes' do
@@ -36,7 +36,7 @@ RSpec.describe ServiceFieldEntity do
end
end
- context 'field with type password' do
+ context 'with field with type password' do
let(:field) { integration_field('password') }
it 'exposes correct attributes but hides password' do
@@ -58,10 +58,10 @@ RSpec.describe ServiceFieldEntity do
end
end
- context 'EmailsOnPush Service' do
+ context 'with EmailsOnPush integration' do
let(:integration) { create(:emails_on_push_integration, send_from_committer_email: '1') }
- context 'field with type checkbox' do
+ context 'with field with type checkbox' do
let(:field) { integration_field('send_from_committer_email') }
it 'exposes correct attributes and casts value to Boolean' do
@@ -78,11 +78,14 @@ RSpec.describe ServiceFieldEntity do
}
is_expected.to include(expected_hash)
- expect(subject[:help]).to include("Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance")
+ expect(subject[:help]).to include(
+ "Send notifications from the committer's email address if the domain " \
+ "matches the domain used by your GitLab instance"
+ )
end
end
- context 'field with type select' do
+ context 'with field with type select' do
let(:field) { integration_field('branches_to_be_notified') }
it 'exposes correct attributes' do
@@ -93,7 +96,12 @@ RSpec.describe ServiceFieldEntity do
title: 'Branches for which notifications are to be sent',
placeholder: nil,
required: nil,
- choices: [['All branches', 'all'], ['Default branch', 'default'], ['Protected branches', 'protected'], ['Default branch and protected branches', 'default_and_protected']],
+ choices: [
+ ['All branches', 'all'],
+ ['Default branch', 'default'],
+ ['Protected branches', 'protected'],
+ ['Default branch and protected branches', 'default_and_protected']
+ ],
help: nil,
value: nil,
checkbox_label: nil
diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb
index e767990d351..bfcaf9552b3 100644
--- a/spec/support/matchers/exceed_query_limit.rb
+++ b/spec/support/matchers/exceed_query_limit.rb
@@ -1,6 +1,68 @@
# frozen_string_literal: true
module ExceedQueryLimitHelpers
+ class QueryDiff
+ def initialize(expected, actual, show_common_queries)
+ @expected = expected
+ @actual = actual
+ @show_common_queries = show_common_queries
+ end
+
+ def diff
+ return combined_counts if @show_common_queries
+
+ combined_counts
+ .transform_values { select_suffixes_with_diffs(_1) }
+ .reject { |_prefix, suffs| suffs.empty? }
+ end
+
+ private
+
+ def select_suffixes_with_diffs(suffs)
+ reject_groups_with_different_parameters(reject_suffixes_with_identical_counts(suffs))
+ end
+
+ def reject_suffixes_with_identical_counts(suffs)
+ suffs.reject { |_k, counts| counts.first == counts.second }
+ end
+
+ # Eliminates groups that differ only in parameters,
+ # to make it easier to debug the output.
+ #
+ # For example, if we have a group `SELECT * FROM users...`,
+ # with the following suffixes
+ # `WHERE id = 1` (counts: N, 0)
+ # `WHERE id = 2` (counts: 0, N)
+ def reject_groups_with_different_parameters(suffs)
+ return suffs if suffs.size != 2
+
+ counts_a, counts_b = suffs.values
+ return {} if counts_a == counts_b.reverse && counts_a.include?(0)
+
+ suffs
+ end
+
+ def expected_counts
+ @expected.transform_values do |suffixes|
+ suffixes.transform_values { |n| [n, 0] }
+ end
+ end
+
+ def recorded_counts
+ @actual.transform_values do |suffixes|
+ suffixes.transform_values { |n| [0, n] }
+ end
+ end
+
+ def combined_counts
+ expected_counts.merge(recorded_counts) do |_k, exp, got|
+ exp.merge(got) do |_k, exp_counts, got_counts|
+ exp_counts.zip(got_counts).map { |a, b| a + b }
+ end
+ end
+ end
+ end
+
MARGINALIA_ANNOTATION_REGEX = %r{\s*\/\*.*\*\/}.freeze
DB_QUERY_RE = Regexp.union([
@@ -108,40 +170,7 @@ module ExceedQueryLimitHelpers
end
def diff_query_counts(expected, actual)
- expected_counts = expected.transform_values do |suffixes|
- suffixes.transform_values { |n| [n, 0] }
- end
- recorded_counts = actual.transform_values do |suffixes|
- suffixes.transform_values { |n| [0, n] }
- end
-
- combined_counts = expected_counts.merge(recorded_counts) do |_k, exp, got|
- exp.merge(got) do |_k, exp_counts, got_counts|
- exp_counts.zip(got_counts).map { |a, b| a + b }
- end
- end
-
- reject_groups_with_matching_counts(combined_counts)
- end
-
- def reject_groups_with_matching_counts(combined_counts)
- return combined_counts if @show_common_queries
-
- combined_counts
- .transform_values { select_suffixes_with_diffs(_1) }
- .reject { |_prefix, suffs| suffs.empty? }
- end
-
- def select_suffixes_with_diffs(suffs)
- # reject when count in LHS is the same as count in RHS
- suffs = suffs.reject { |_k, counts| counts.first == counts.second }
-
- # Reject common case of N queries on LHS and N on right, but with different parameters
- # accepts as equivalent if a == [0, 1] and b == [1, 0], for example
- keys = suffs.keys
- return {} if keys.size == 2 && suffs[keys.first] == suffs[keys.second].reverse
-
- suffs
+ QueryDiff.new(expected, actual, @show_common_queries).diff
end
def diff_query_group_message(query, suffixes)
diff --git a/spec/workers/clusters/applications/activate_service_worker_spec.rb b/spec/workers/clusters/applications/activate_integration_worker_spec.rb
index d13ff76613c..ecb49be5a4b 100644
--- a/spec/workers/clusters/applications/activate_service_worker_spec.rb
+++ b/spec/workers/clusters/applications/activate_integration_worker_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe Clusters::Applications::ActivateServiceWorker, '#perform' do
- context 'cluster exists' do
+RSpec.describe Clusters::Applications::ActivateIntegrationWorker, '#perform' do
+ context 'when cluster exists' do
describe 'prometheus integration' do
let(:integration_name) { 'prometheus' }
@@ -11,7 +11,7 @@ RSpec.describe Clusters::Applications::ActivateServiceWorker, '#perform' do
create(:clusters_integrations_prometheus, cluster: cluster)
end
- context 'cluster type: group' do
+ context 'with cluster type: group' do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:cluster) { create(:cluster_for_group, groups: [group]) }
@@ -22,7 +22,7 @@ RSpec.describe Clusters::Applications::ActivateServiceWorker, '#perform' do
end
end
- context 'cluster type: project' do
+ context 'with cluster type: project' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, projects: [project]) }
@@ -32,7 +32,7 @@ RSpec.describe Clusters::Applications::ActivateServiceWorker, '#perform' do
end
end
- context 'cluster type: instance' do
+ context 'with cluster type: instance' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, :instance) }
@@ -40,11 +40,20 @@ RSpec.describe Clusters::Applications::ActivateServiceWorker, '#perform' do
expect { described_class.new.perform(cluster.id, integration_name) }
.to change { project.reload.prometheus_integration&.active }.from(nil).to(true)
end
+
+ context 'when using the old worker class' do
+ let(:described_class) { Clusters::Applications::ActivateServiceWorker }
+
+ it 'ensures Prometheus integration is activated' do
+ expect { described_class.new.perform(cluster.id, integration_name) }
+ .to change { project.reload.prometheus_integration&.active }.from(nil).to(true)
+ end
+ end
end
end
end
- context 'cluster does not exist' do
+ context 'when cluster does not exist' do
it 'does not raise Record Not Found error' do
expect { described_class.new.perform(0, 'ignored in this context') }.not_to raise_error
end
diff --git a/spec/workers/clusters/applications/deactivate_service_worker_spec.rb b/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb
index 77788cfa893..3f0188eee23 100644
--- a/spec/workers/clusters/applications/deactivate_service_worker_spec.rb
+++ b/spec/workers/clusters/applications/deactivate_integration_worker_spec.rb
@@ -2,20 +2,22 @@
require 'spec_helper'
-RSpec.describe Clusters::Applications::DeactivateServiceWorker, '#perform' do
- context 'cluster exists' do
+RSpec.describe Clusters::Applications::DeactivateIntegrationWorker, '#perform' do
+ context 'when cluster exists' do
describe 'prometheus integration' do
let(:integration_name) { 'prometheus' }
let!(:integration) { create(:clusters_integrations_prometheus, cluster: cluster) }
- context 'prometheus integration exists' do
- let!(:prometheus_integration) { create(:prometheus_integration, project: project, manual_configuration: false, active: true) }
+ context 'when prometheus integration exists' do
+ let!(:prometheus_integration) do
+ create(:prometheus_integration, project: project, manual_configuration: false, active: true)
+ end
before do
integration.delete # prometheus integration before save synchronises active stated with integration existence.
end
- context 'cluster type: group' do
+ context 'with cluster type: group' do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:cluster) { create(:cluster_for_group, groups: [group]) }
@@ -26,7 +28,7 @@ RSpec.describe Clusters::Applications::DeactivateServiceWorker, '#perform' do
end
end
- context 'cluster type: project' do
+ context 'with cluster type: project' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, projects: [project]) }
@@ -36,7 +38,7 @@ RSpec.describe Clusters::Applications::DeactivateServiceWorker, '#perform' do
end
end
- context 'cluster type: instance' do
+ context 'with cluster type: instance' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, :instance) }
@@ -44,11 +46,20 @@ RSpec.describe Clusters::Applications::DeactivateServiceWorker, '#perform' do
expect { described_class.new.perform(cluster.id, integration_name) }
.to change { prometheus_integration.reload.active }.from(true).to(false)
end
+
+ context 'when using the old worker class' do
+ let(:described_class) { Clusters::Applications::ActivateServiceWorker }
+
+ it 'ensures Prometheus integration is deactivated' do
+ expect { described_class.new.perform(cluster.id, integration_name) }
+ .to change { prometheus_integration.reload.active }.from(true).to(false)
+ end
+ end
end
end
- context 'prometheus integration does not exist' do
- context 'cluster type: project' do
+ context 'when prometheus integration does not exist' do
+ context 'with cluster type: project' do
let(:project) { create(:project) }
let(:cluster) { create(:cluster, projects: [project]) }
@@ -60,7 +71,7 @@ RSpec.describe Clusters::Applications::DeactivateServiceWorker, '#perform' do
end
end
- context 'cluster does not exist' do
+ context 'when cluster does not exist' do
it 'raises Record Not Found error' do
expect { described_class.new.perform(0, 'ignored in this context') }.to raise_error(ActiveRecord::RecordNotFound)
end
diff --git a/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb b/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb
index 0191a2898b2..d1dd1cd738b 100644
--- a/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb
+++ b/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Clusters::Applications::WaitForUninstallAppWorker, '#perform' do
subject { described_class.new.perform(app_name, app_id) }
- context 'app exists' do
+ context 'when app exists' do
let(:service) { instance_double(Clusters::Applications::CheckUninstallProgressService) }
it 'calls the check service' do
@@ -20,7 +20,7 @@ RSpec.describe Clusters::Applications::WaitForUninstallAppWorker, '#perform' do
end
end
- context 'app does not exist' do
+ context 'when app does not exist' do
let(:app_id) { 0 }
it 'does not call the check service' do
diff --git a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
index f141a1ad7ad..eeccdbd0e2d 100644
--- a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
+++ b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_queues do
+RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_shared_state do
let(:job_tracker) do
described_class.new('namespace')
end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index fb8ff23f8d8..eaf75cccb3e 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -180,7 +180,9 @@ RSpec.describe 'Every Sidekiq worker' do
'ClusterWaitForAppInstallationWorker' => 3,
'ClusterWaitForAppUpdateWorker' => 3,
'ClusterWaitForIngressIpAddressWorker' => 3,
+ 'Clusters::Applications::ActivateIntegrationWorker' => 3,
'Clusters::Applications::ActivateServiceWorker' => 3,
+ 'Clusters::Applications::DeactivateIntegrationWorker' => 3,
'Clusters::Applications::DeactivateServiceWorker' => 3,
'Clusters::Applications::UninstallWorker' => 3,
'Clusters::Applications::WaitForUninstallAppWorker' => 3,