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>2021-10-12 18:12:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-12 18:12:08 +0300
commit13f15365a344255ded8b3bf6586716b0963be440 (patch)
tree48b5290c7f84fab4e79577b1d463798feaa4257f /spec
parent57a3a42c88f6e7dbcfd388a5c83302f0bb666023 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/alerting/notifications_controller_spec.rb112
-rw-r--r--spec/features/cycle_analytics_spec.rb59
-rw-r--r--spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js22
-rw-r--r--spec/frontend/cycle_analytics/base_spec.js8
-rw-r--r--spec/frontend/cycle_analytics/mock_data.js27
-rw-r--r--spec/frontend/cycle_analytics/store/actions_spec.js37
-rw-r--r--spec/frontend/cycle_analytics/store/getters_spec.js27
-rw-r--r--spec/frontend/cycle_analytics/store/mutations_spec.js29
-rw-r--r--spec/graphql/types/issue_type_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/templates_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/attributes_permitter_spec.rb7
-rw-r--r--spec/lib/gitlab/subscription_portal_spec.rb1
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb46
-rw-r--r--spec/models/deployment_spec.rb32
-rw-r--r--spec/models/product_analytics_event_spec.rb11
-rw-r--r--spec/requests/api/graphql/project/issues_spec.rb32
-rw-r--r--spec/services/deployments/older_deployments_drop_service_spec.rb2
-rw-r--r--spec/support/database/cross-database-modification-allowlist.yml1
-rw-r--r--spec/support/database/cross-join-allowlist.yml2
19 files changed, 310 insertions, 154 deletions
diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb
index fe0c4ce00bf..2fff8026b22 100644
--- a/spec/controllers/projects/alerting/notifications_controller_spec.rb
+++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Projects::Alerting::NotificationsController do
+ include HttpBasicAuthHelpers
+
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) }
@@ -53,86 +55,96 @@ RSpec.describe Projects::Alerting::NotificationsController do
end
end
- context 'bearer token' do
- context 'when set' do
- context 'when extractable' do
- before do
- request.headers['HTTP_AUTHORIZATION'] = 'Bearer some token'
- end
-
- it 'extracts bearer token' do
- expect(notify_service).to receive(:execute).with('some token', nil)
-
- make_request
- end
-
- context 'with a corresponding integration' do
- context 'with integration parameters specified' do
- let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
+ shared_examples 'a working token' do
+ it 'extracts token' do
+ expect(notify_service).to receive(:execute).with('some token', nil)
- let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) }
-
- context 'the integration is active' do
- it 'extracts and finds the integration' do
- expect(notify_service).to receive(:execute).with('some token', integration)
+ make_request
+ end
- make_request
- end
- end
+ context 'with a corresponding integration' do
+ context 'with integration parameters specified' do
+ let_it_be_with_reload(:integration) { create(:alert_management_http_integration, project: project) }
- context 'when the integration is inactive' do
- before do
- integration.update!(active: false)
- end
+ let(:params) { project_params(endpoint_identifier: integration.endpoint_identifier, name: integration.name) }
- it 'does not find an integration' do
- expect(notify_service).to receive(:execute).with('some token', nil)
+ context 'the integration is active' do
+ it 'extracts and finds the integration' do
+ expect(notify_service).to receive(:execute).with('some token', integration)
- make_request
- end
- end
+ make_request
end
+ end
- context 'without integration parameters specified' do
- let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) }
+ context 'when the integration is inactive' do
+ before do
+ integration.update!(active: false)
+ end
- it 'extracts and finds the legacy integration' do
- expect(notify_service).to receive(:execute).with('some token', integration)
+ it 'does not find an integration' do
+ expect(notify_service).to receive(:execute).with('some token', nil)
- make_request
- end
+ make_request
end
end
end
- context 'when inextractable' do
- it 'passes nil for a non-bearer token' do
- request.headers['HTTP_AUTHORIZATION'] = 'some token'
+ context 'without integration parameters specified' do
+ let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: project) }
- expect(notify_service).to receive(:execute).with(nil, nil)
+ it 'extracts and finds the legacy integration' do
+ expect(notify_service).to receive(:execute).with('some token', integration)
make_request
end
end
end
+ end
- context 'when missing' do
- it 'passes nil' do
- expect(notify_service).to receive(:execute).with(nil, nil)
-
- make_request
+ context 'with bearer token' do
+ context 'when set' do
+ before do
+ request.headers.merge(build_token_auth_header('some token'))
end
+
+ it_behaves_like 'a working token'
+ end
+ end
+
+ context 'with basic auth token' do
+ before do
+ request.headers.merge basic_auth_header(nil, 'some token')
+ end
+
+ it_behaves_like 'a working token'
+ end
+
+ context 'when inextractable token' do
+ it 'passes nil for a non-bearer token' do
+ request.headers['HTTP_AUTHORIZATION'] = 'some token'
+
+ expect(notify_service).to receive(:execute).with(nil, nil)
+
+ make_request
+ end
+ end
+
+ context 'when missing token' do
+ it 'passes nil' do
+ expect(notify_service).to receive(:execute).with(nil, nil)
+
+ make_request
end
end
end
- context 'generic alert payload' do
+ context 'with generic alert payload' do
it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do
let(:payload) { { title: 'Alert title' } }
end
end
- context 'Prometheus alert payload' do
+ context 'with Prometheus alert payload' do
include PrometheusHelpers
it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index bec474f6cfe..34a55118cb3 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -7,10 +7,13 @@ RSpec.describe 'Value Stream Analytics', :js do
let_it_be(:guest) { create(:user) }
let_it_be(:stage_table_selector) { '[data-testid="vsa-stage-table"]' }
let_it_be(:stage_table_event_selector) { '[data-testid="vsa-stage-event"]' }
+ let_it_be(:stage_table_event_title_selector) { '[data-testid="vsa-stage-event-title"]' }
+ let_it_be(:stage_table_pagination_selector) { '[data-testid="vsa-stage-pagination"]' }
+ let_it_be(:stage_table_duration_column_header_selector) { '[data-testid="vsa-stage-header-duration"]' }
let_it_be(:metrics_selector) { "[data-testid='vsa-time-metrics']" }
let_it_be(:metric_value_selector) { "[data-testid='displayValue']" }
- let(:stage_table) { page.find(stage_table_selector) }
+ let(:stage_table) { find(stage_table_selector) }
let(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
let(:milestone) { create(:milestone, project: project) }
@@ -53,6 +56,7 @@ RSpec.describe 'Value Stream Analytics', :js do
# So setting the date range to be the last 2 days should skip past the existing data
from = 2.days.ago.strftime("%Y-%m-%d")
to = 1.day.ago.strftime("%Y-%m-%d")
+ max_items_per_page = 20
around do |example|
travel_to(5.days.ago) { example.run }
@@ -60,9 +64,8 @@ RSpec.describe 'Value Stream Analytics', :js do
before do
project.add_maintainer(user)
- create_list(:issue, 2, project: project, created_at: 2.weeks.ago, milestone: milestone)
-
create_cycle(user, project, issue, mr, milestone, pipeline)
+ create_list(:issue, max_items_per_page, project: project, created_at: 2.weeks.ago, milestone: milestone)
deploy_master(user, project)
issue.metrics.update!(first_mentioned_in_commit_at: issue.metrics.first_associated_with_milestone_at + 1.hour)
@@ -81,6 +84,8 @@ RSpec.describe 'Value Stream Analytics', :js do
wait_for_requests
end
+ let(:stage_table_events) { stage_table.all(stage_table_event_selector) }
+
it 'displays metrics' do
metrics_tiles = page.find(metrics_selector)
@@ -112,20 +117,62 @@ RSpec.describe 'Value Stream Analytics', :js do
end
it 'can filter the issues by date' do
- expect(stage_table.all(stage_table_event_selector).length).to eq(3)
+ expect(page).to have_selector(stage_table_event_selector)
set_daterange(from, to)
- expect(stage_table.all(stage_table_event_selector).length).to eq(0)
+ expect(page).not_to have_selector(stage_table_event_selector)
+ expect(page).not_to have_selector(stage_table_pagination_selector)
end
it 'can filter the metrics by date' do
- expect(metrics_values).to eq(["3.0", "2.0", "1.0", "0.0"])
+ expect(metrics_values).to match_array(["21.0", "2.0", "1.0", "0.0"])
set_daterange(from, to)
expect(metrics_values).to eq(['-'] * 4)
end
+
+ it 'can sort records' do
+ # NOTE: checking that the string changes should suffice
+ # depending on the order the tests are run we might run into problems with hard coded strings
+ original_first_title = first_stage_title
+ stage_time_column.click
+
+ expect_to_be_sorted "descending"
+ expect(first_stage_title).not_to have_text(original_first_title, exact: true)
+
+ stage_time_column.click
+
+ expect_to_be_sorted "ascending"
+ expect(first_stage_title).to have_text(original_first_title, exact: true)
+ end
+
+ it 'paginates the results' do
+ original_first_title = first_stage_title
+
+ expect(page).to have_selector(stage_table_pagination_selector)
+
+ go_to_next_page
+
+ expect(page).not_to have_text(original_first_title, exact: true)
+ end
+
+ def stage_time_column
+ stage_table.find(stage_table_duration_column_header_selector).ancestor("th")
+ end
+
+ def first_stage_title
+ stage_table.all(stage_table_event_title_selector).first.text
+ end
+
+ def expect_to_be_sorted(direction)
+ expect(stage_time_column['aria-sort']).to eq(direction)
+ end
+
+ def go_to_next_page
+ page.find(stage_table_pagination_selector).find_link("Next").click
+ end
end
end
diff --git a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
index 36b81b3eb28..5d681c7da4f 100644
--- a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
+++ b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js
@@ -2,6 +2,7 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import { TEST_HOST } from 'helpers/test_constants';
+import waitForPromises from 'helpers/wait_for_promises';
import ProjectsDropdownFilter from '~/analytics/shared/components/projects_dropdown_filter.vue';
import getProjects from '~/analytics/shared/graphql/projects.query.graphql';
@@ -65,7 +66,7 @@ describe('ProjectsDropdownFilter component', () => {
const createWithMockDropdown = (props) => {
createComponent(props, { GlDropdown: MockGlDropdown });
- return wrapper.vm.$nextTick();
+ return waitForPromises();
};
afterEach(() => {
@@ -73,6 +74,7 @@ describe('ProjectsDropdownFilter component', () => {
});
const findHighlightedItems = () => wrapper.findByTestId('vsa-highlighted-items');
+ const findUnhighlightedItems = () => wrapper.findByTestId('vsa-default-items');
const findHighlightedItemsTitle = () => wrapper.findByText('Selected');
const findClearAllButton = () => wrapper.findByText('Clear all');
@@ -197,6 +199,24 @@ describe('ProjectsDropdownFilter component', () => {
});
});
+ describe('with a selected project and search term', () => {
+ beforeEach(async () => {
+ await createWithMockDropdown({ multiSelect: true });
+
+ selectDropdownItemAtIndex(0);
+ wrapper.setData({ searchTerm: 'this is a very long search string' });
+ });
+
+ it('renders the highlighted items', async () => {
+ expect(findUnhighlightedItems().findAll('li').length).toBe(1);
+ });
+
+ it('hides the unhighlighted items that do not match the string', async () => {
+ expect(findUnhighlightedItems().findAll('li').length).toBe(1);
+ expect(findUnhighlightedItems().text()).toContain('No matching results');
+ });
+ });
+
describe('when passed an array of defaultProject as prop', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/frontend/cycle_analytics/base_spec.js b/spec/frontend/cycle_analytics/base_spec.js
index 5d3361bfa35..9a9415cc12a 100644
--- a/spec/frontend/cycle_analytics/base_spec.js
+++ b/spec/frontend/cycle_analytics/base_spec.js
@@ -19,6 +19,7 @@ import {
createdAfter,
currentGroup,
stageCounts,
+ initialPaginationState as pagination,
} from './mock_data';
const selectedStageEvents = issueEvents.events;
@@ -81,6 +82,7 @@ const findOverviewMetrics = () => wrapper.findComponent(ValueStreamMetrics);
const findStageTable = () => wrapper.findComponent(StageTable);
const findStageEvents = () => findStageTable().props('stageEvents');
const findEmptyStageTitle = () => wrapper.findComponent(GlEmptyState).props('title');
+const findPagination = () => wrapper.findByTestId('vsa-stage-pagination');
const hasMetricsRequests = (reqs) => {
const foundReqs = findOverviewMetrics().props('requests');
@@ -90,7 +92,7 @@ const hasMetricsRequests = (reqs) => {
describe('Value stream analytics component', () => {
beforeEach(() => {
- wrapper = createComponent({ initialState: { selectedStage, selectedStageEvents } });
+ wrapper = createComponent({ initialState: { selectedStage, selectedStageEvents, pagination } });
});
afterEach(() => {
@@ -153,6 +155,10 @@ describe('Value stream analytics component', () => {
expect(findLoadingIcon().exists()).toBe(false);
});
+ it('renders pagination', () => {
+ expect(findPagination().exists()).toBe(true);
+ });
+
describe('with `cycleAnalyticsForGroups=true` license', () => {
beforeEach(() => {
wrapper = createComponent({ initialState: { features: { cycleAnalyticsForGroups: true } } });
diff --git a/spec/frontend/cycle_analytics/mock_data.js b/spec/frontend/cycle_analytics/mock_data.js
index d9659d5d4c3..9a89ac23b21 100644
--- a/spec/frontend/cycle_analytics/mock_data.js
+++ b/spec/frontend/cycle_analytics/mock_data.js
@@ -1,6 +1,12 @@
import { getJSONFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
-import { DEFAULT_VALUE_STREAM, DEFAULT_DAYS_IN_PAST } from '~/cycle_analytics/constants';
+import {
+ DEFAULT_VALUE_STREAM,
+ DEFAULT_DAYS_IN_PAST,
+ PAGINATION_TYPE,
+ PAGINATION_SORT_DIRECTION_DESC,
+ PAGINATION_SORT_FIELD_END_EVENT,
+} from '~/cycle_analytics/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { getDateInPast } from '~/lib/utils/datetime_utility';
@@ -256,3 +262,22 @@ export const rawValueStreamStages = customizableStagesAndEvents.stages;
export const valueStreamStages = rawValueStreamStages.map((s) =>
convertObjectPropsToCamelCase(s, { deep: true }),
);
+
+export const initialPaginationQuery = {
+ page: 15,
+ sort: PAGINATION_SORT_FIELD_END_EVENT,
+ direction: PAGINATION_SORT_DIRECTION_DESC,
+};
+
+export const initialPaginationState = {
+ ...initialPaginationQuery,
+ page: null,
+ hasNextPage: false,
+};
+
+export const basePaginationResult = {
+ pagination: PAGINATION_TYPE,
+ sort: PAGINATION_SORT_FIELD_END_EVENT,
+ direction: PAGINATION_SORT_DIRECTION_DESC,
+ page: null,
+};
diff --git a/spec/frontend/cycle_analytics/store/actions_spec.js b/spec/frontend/cycle_analytics/store/actions_spec.js
index 97b5bd03e18..993e6b6b73a 100644
--- a/spec/frontend/cycle_analytics/store/actions_spec.js
+++ b/spec/frontend/cycle_analytics/store/actions_spec.js
@@ -11,6 +11,8 @@ import {
currentGroup,
createdAfter,
createdBefore,
+ initialPaginationState,
+ reviewEvents,
} from '../mock_data';
const { id: groupId, path: groupPath } = currentGroup;
@@ -31,7 +33,13 @@ const mockSetDateActionCommit = {
type: 'SET_DATE_RANGE',
};
-const defaultState = { ...getters, selectedValueStream, createdAfter, createdBefore };
+const defaultState = {
+ ...getters,
+ selectedValueStream,
+ createdAfter,
+ createdBefore,
+ pagination: initialPaginationState,
+};
describe('Project Value Stream Analytics actions', () => {
let state;
@@ -112,6 +120,21 @@ describe('Project Value Stream Analytics actions', () => {
});
});
+ describe('updateStageTablePagination', () => {
+ beforeEach(() => {
+ state = { ...state, selectedStage };
+ });
+
+ it(`will dispatch the "fetchStageData" action and commit the 'SET_PAGINATION' mutation`, () => {
+ return testAction({
+ action: actions.updateStageTablePagination,
+ state,
+ expectedMutations: [{ type: 'SET_PAGINATION' }],
+ expectedActions: [{ type: 'fetchStageData', payload: selectedStage.id }],
+ });
+ });
+ });
+
describe('fetchCycleAnalyticsData', () => {
beforeEach(() => {
state = { ...defaultState, endpoints: mockEndpoints };
@@ -154,6 +177,10 @@ describe('Project Value Stream Analytics actions', () => {
describe('fetchStageData', () => {
const mockStagePath = /value_streams\/\w+\/stages\/\w+\/records/;
+ const headers = {
+ 'X-Next-Page': 2,
+ 'X-Page': 1,
+ };
beforeEach(() => {
state = {
@@ -162,7 +189,7 @@ describe('Project Value Stream Analytics actions', () => {
selectedStage,
};
mock = new MockAdapter(axios);
- mock.onGet(mockStagePath).reply(httpStatusCodes.OK);
+ mock.onGet(mockStagePath).reply(httpStatusCodes.OK, reviewEvents, headers);
});
it(`commits the 'RECEIVE_STAGE_DATA_SUCCESS' mutation`, () =>
@@ -170,7 +197,11 @@ describe('Project Value Stream Analytics actions', () => {
action: actions.fetchStageData,
state,
payload: {},
- expectedMutations: [{ type: 'REQUEST_STAGE_DATA' }, { type: 'RECEIVE_STAGE_DATA_SUCCESS' }],
+ expectedMutations: [
+ { type: 'REQUEST_STAGE_DATA' },
+ { type: 'RECEIVE_STAGE_DATA_SUCCESS', payload: reviewEvents },
+ { type: 'SET_PAGINATION', payload: { hasNextPage: true, page: 1 } },
+ ],
expectedActions: [],
}));
diff --git a/spec/frontend/cycle_analytics/store/getters_spec.js b/spec/frontend/cycle_analytics/store/getters_spec.js
index c47a30a5f79..c9208045a68 100644
--- a/spec/frontend/cycle_analytics/store/getters_spec.js
+++ b/spec/frontend/cycle_analytics/store/getters_spec.js
@@ -1,17 +1,42 @@
import * as getters from '~/cycle_analytics/store/getters';
+
import {
allowedStages,
stageMedians,
transformedProjectStagePathData,
selectedStage,
stageCounts,
+ basePaginationResult,
+ initialPaginationState,
} from '../mock_data';
describe('Value stream analytics getters', () => {
+ let state = {};
+
describe('pathNavigationData', () => {
it('returns the transformed data', () => {
- const state = { stages: allowedStages, medians: stageMedians, selectedStage, stageCounts };
+ state = { stages: allowedStages, medians: stageMedians, selectedStage, stageCounts };
expect(getters.pathNavigationData(state)).toEqual(transformedProjectStagePathData);
});
});
+
+ describe('paginationParams', () => {
+ beforeEach(() => {
+ state = { pagination: initialPaginationState };
+ });
+
+ it('returns the `pagination` type', () => {
+ expect(getters.paginationParams(state)).toEqual(basePaginationResult);
+ });
+
+ it('returns the `sort` type', () => {
+ expect(getters.paginationParams(state)).toEqual(basePaginationResult);
+ });
+
+ it('with page=10, sets the `page` property', () => {
+ const page = 10;
+ state = { pagination: { ...initialPaginationState, page } };
+ expect(getters.paginationParams(state)).toEqual({ ...basePaginationResult, page });
+ });
+ });
});
diff --git a/spec/frontend/cycle_analytics/store/mutations_spec.js b/spec/frontend/cycle_analytics/store/mutations_spec.js
index 628e2a4e7ae..4860225c995 100644
--- a/spec/frontend/cycle_analytics/store/mutations_spec.js
+++ b/spec/frontend/cycle_analytics/store/mutations_spec.js
@@ -2,6 +2,10 @@ import { useFakeDate } from 'helpers/fake_date';
import * as types from '~/cycle_analytics/store/mutation_types';
import mutations from '~/cycle_analytics/store/mutations';
import {
+ PAGINATION_SORT_FIELD_END_EVENT,
+ PAGINATION_SORT_DIRECTION_DESC,
+} from '~/cycle_analytics/constants';
+import {
selectedStage,
rawIssueEvents,
issueEvents,
@@ -12,6 +16,7 @@ import {
formattedStageMedians,
rawStageCounts,
stageCounts,
+ initialPaginationState as pagination,
} from '../mock_data';
let state;
@@ -25,7 +30,7 @@ describe('Project Value Stream Analytics mutations', () => {
useFakeDate(2020, 6, 18);
beforeEach(() => {
- state = {};
+ state = { pagination };
});
afterEach(() => {
@@ -88,16 +93,18 @@ describe('Project Value Stream Analytics mutations', () => {
});
it.each`
- mutation | payload | stateKey | value
- ${types.SET_DATE_RANGE} | ${mockSetDatePayload} | ${'createdAfter'} | ${mockCreatedAfter}
- ${types.SET_DATE_RANGE} | ${mockSetDatePayload} | ${'createdBefore'} | ${mockCreatedBefore}
- ${types.SET_LOADING} | ${true} | ${'isLoading'} | ${true}
- ${types.SET_LOADING} | ${false} | ${'isLoading'} | ${false}
- ${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream}
- ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]}
- ${types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS} | ${{ stages: rawValueStreamStages }} | ${'stages'} | ${valueStreamStages}
- ${types.RECEIVE_STAGE_MEDIANS_SUCCESS} | ${rawStageMedians} | ${'medians'} | ${formattedStageMedians}
- ${types.RECEIVE_STAGE_COUNTS_SUCCESS} | ${rawStageCounts} | ${'stageCounts'} | ${stageCounts}
+ mutation | payload | stateKey | value
+ ${types.SET_DATE_RANGE} | ${mockSetDatePayload} | ${'createdAfter'} | ${mockCreatedAfter}
+ ${types.SET_DATE_RANGE} | ${mockSetDatePayload} | ${'createdBefore'} | ${mockCreatedBefore}
+ ${types.SET_LOADING} | ${true} | ${'isLoading'} | ${true}
+ ${types.SET_LOADING} | ${false} | ${'isLoading'} | ${false}
+ ${types.SET_SELECTED_VALUE_STREAM} | ${selectedValueStream} | ${'selectedValueStream'} | ${selectedValueStream}
+ ${types.SET_PAGINATION} | ${pagination} | ${'pagination'} | ${{ ...pagination, sort: PAGINATION_SORT_FIELD_END_EVENT, direction: PAGINATION_SORT_DIRECTION_DESC }}
+ ${types.SET_PAGINATION} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} | ${'pagination'} | ${{ ...pagination, sort: 'duration', direction: 'asc' }}
+ ${types.RECEIVE_VALUE_STREAMS_SUCCESS} | ${[selectedValueStream]} | ${'valueStreams'} | ${[selectedValueStream]}
+ ${types.RECEIVE_VALUE_STREAM_STAGES_SUCCESS} | ${{ stages: rawValueStreamStages }} | ${'stages'} | ${valueStreamStages}
+ ${types.RECEIVE_STAGE_MEDIANS_SUCCESS} | ${rawStageMedians} | ${'medians'} | ${formattedStageMedians}
+ ${types.RECEIVE_STAGE_COUNTS_SUCCESS} | ${rawStageCounts} | ${'stageCounts'} | ${stageCounts}
`(
'$mutation with $payload will set $stateKey to $value',
({ mutation, payload, stateKey, value }) => {
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index 559f347810b..c0a0fdf3b0b 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
confidential hidden discussion_locked upvotes downvotes merge_requests_count user_notes_count user_discussions_count web_path web_url relative_position
emails_disabled subscribed time_estimate total_time_spent human_time_estimate human_total_time_spent closed_at created_at updated_at task_completion_status
design_collection alert_management_alert severity current_user_todos moved moved_to
- create_note_email timelogs project_id]
+ create_note_email timelogs project_id customer_relations_contacts]
fields.each do |field_name|
expect(described_class).to have_graphql_field(field_name)
diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb
index 81fc66c4a11..cdda7e953d0 100644
--- a/spec/lib/gitlab/ci/templates/templates_spec.rb
+++ b/spec/lib/gitlab/ci/templates/templates_spec.rb
@@ -13,13 +13,6 @@ RSpec.describe 'CI YML Templates' do
excluded + ["Terraform.gitlab-ci.yml"]
end
- before do
- stub_feature_flags(
- redirect_to_latest_template_terraform: false,
- redirect_to_latest_template_security_api_fuzzing: false,
- redirect_to_latest_template_security_dast: false)
- end
-
shared_examples 'require default stages to be included' do
it 'require default stages to be included' do
expect(subject.stages).to include(*Gitlab::Ci::Config::Entry::Stages.default)
diff --git a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
index 61f09758328..2b974f8985d 100644
--- a/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
+++ b/spec/lib/gitlab/import_export/attributes_permitter_spec.rb
@@ -92,6 +92,13 @@ RSpec.describe Gitlab::ImportExport::AttributesPermitter do
:boards | true
:custom_attributes | true
:labels | true
+ :protected_branches | true
+ :protected_tags | true
+ :create_access_levels | true
+ :merge_access_levels | true
+ :push_access_levels | true
+ :releases | true
+ :links | true
end
with_them do
diff --git a/spec/lib/gitlab/subscription_portal_spec.rb b/spec/lib/gitlab/subscription_portal_spec.rb
index 5a2d5be3925..d48c3ee68c0 100644
--- a/spec/lib/gitlab/subscription_portal_spec.rb
+++ b/spec/lib/gitlab/subscription_portal_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe ::Gitlab::SubscriptionPortal do
before do
stub_env('CUSTOMER_PORTAL_URL', env_value)
+ stub_feature_flags(new_customersdot_staging_url: false)
end
describe '.default_subscriptions_url' do
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 756c728f998..05ceceae996 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -724,7 +724,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(counts_monthly[:projects_with_alerts_created]).to eq(1)
expect(counts_monthly[:projects]).to eq(1)
expect(counts_monthly[:packages]).to eq(1)
- expect(counts_monthly[:promoted_issues]).to eq(1)
+ expect(counts_monthly[:promoted_issues]).to eq(Gitlab::UsageData::DEPRECATED_VALUE)
end
end
@@ -1419,48 +1419,4 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
end
-
- describe '.snowplow_event_counts' do
- let_it_be(:time_period) { { collector_tstamp: 8.days.ago..1.day.ago } }
-
- context 'when self-monitoring project exists' do
- let_it_be(:project) { create(:project) }
-
- before do
- stub_application_setting(self_monitoring_project: project)
- end
-
- context 'and product_analytics FF is enabled for it' do
- before do
- stub_feature_flags(product_analytics_tracking: true)
-
- create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote')
- create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote', collector_tstamp: 2.days.ago)
- create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote', collector_tstamp: 9.days.ago)
-
- create(:product_analytics_event, project: project, se_category: 'foo', se_action: 'bar', collector_tstamp: 2.days.ago)
- end
-
- it 'returns promoted_issues for the time period' do
- expect(described_class.snowplow_event_counts(time_period)[:promoted_issues]).to eq(1)
- end
- end
-
- context 'and product_analytics FF is disabled' do
- before do
- stub_feature_flags(product_analytics_tracking: false)
- end
-
- it 'returns an empty hash' do
- expect(described_class.snowplow_event_counts(time_period)).to eq({})
- end
- end
- end
-
- context 'when self-monitoring project does not exist' do
- it 'returns an empty hash' do
- expect(described_class.snowplow_event_counts(time_period)).to eq({})
- end
- end
- end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index a0e5e9cbfe4..acccf2c39c4 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -456,18 +456,6 @@ RSpec.describe Deployment do
end
end
- describe 'with_deployable' do
- subject { described_class.with_deployable }
-
- it 'retrieves deployments with deployable builds' do
- with_deployable = create(:deployment)
- create(:deployment, deployable: nil)
- create(:deployment, deployable_type: 'CommitStatus', deployable_id: non_existing_record_id)
-
- is_expected.to contain_exactly(with_deployable)
- end
- end
-
describe 'visible' do
subject { described_class.visible }
@@ -613,6 +601,26 @@ RSpec.describe Deployment do
end
end
+ describe '.builds' do
+ let!(:deployment1) { create(:deployment) }
+ let!(:deployment2) { create(:deployment) }
+ let!(:deployment3) { create(:deployment) }
+
+ subject { described_class.builds }
+
+ it 'retrieves builds for the deployments' do
+ is_expected.to match_array(
+ [deployment1.deployable, deployment2.deployable, deployment3.deployable])
+ end
+
+ it 'does not fetch the null deployable_ids' do
+ deployment3.update!(deployable_id: nil, deployable_type: nil)
+
+ is_expected.to match_array(
+ [deployment1.deployable, deployment2.deployable])
+ end
+ end
+
describe '#previous_deployment' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/models/product_analytics_event_spec.rb b/spec/models/product_analytics_event_spec.rb
index 286729b8398..801e6dd5e10 100644
--- a/spec/models/product_analytics_event_spec.rb
+++ b/spec/models/product_analytics_event_spec.rb
@@ -36,17 +36,6 @@ RSpec.describe ProductAnalyticsEvent, type: :model do
it { expect(described_class.count_by_graph('platform', 30.days)).to eq({ 'app' => 1, 'mobile' => 1, 'web' => 2 }) }
end
- describe '.by_category_and_action' do
- let_it_be(:event) { create(:product_analytics_event, se_category: 'catA', se_action: 'actA') }
-
- before do
- create(:product_analytics_event, se_category: 'catA', se_action: 'actB')
- create(:product_analytics_event, se_category: 'catB', se_action: 'actA')
- end
-
- it { expect(described_class.by_category_and_action('catA', 'actA')).to match_array([event]) }
- end
-
describe '.count_collector_tstamp_by_day' do
let_it_be(:time_now) { Time.zone.now }
let_it_be(:time_ago) { Time.zone.now - 5.days }
diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb
index a62ce12a3b0..1c6d6ce4707 100644
--- a/spec/requests/api/graphql/project/issues_spec.rb
+++ b/spec/requests/api/graphql/project/issues_spec.rb
@@ -5,7 +5,8 @@ require 'spec_helper'
RSpec.describe 'getting an issue list for a project' do
include GraphqlHelpers
- let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, :public, group: group) }
let_it_be(:current_user) { create(:user) }
let_it_be(:issue_a, reload: true) { create(:issue, project: project, discussion_locked: true) }
let_it_be(:issue_b, reload: true) { create(:issue, :with_alert, project: project) }
@@ -409,6 +410,35 @@ RSpec.describe 'getting an issue list for a project' do
end
end
+ context 'when fetching customer_relations_contacts' do
+ let(:fields) do
+ <<~QUERY
+ nodes {
+ id
+ customerRelationsContacts {
+ nodes {
+ firstName
+ }
+ }
+ }
+ QUERY
+ end
+
+ def clean_state_query
+ run_with_clean_state(query, context: { current_user: current_user })
+ end
+
+ it 'avoids N+1 queries' do
+ create(:contact, group_id: group.id, issues: [issue_a])
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) { clean_state_query }
+
+ create(:contact, group_id: group.id, issues: [issue_a])
+
+ expect { clean_state_query }.not_to exceed_all_query_limit(control)
+ end
+ end
+
context 'when fetching labels' do
let(:fields) do
<<~QUERY
diff --git a/spec/services/deployments/older_deployments_drop_service_spec.rb b/spec/services/deployments/older_deployments_drop_service_spec.rb
index 6152a95cc3c..e6fd6725d7d 100644
--- a/spec/services/deployments/older_deployments_drop_service_spec.rb
+++ b/spec/services/deployments/older_deployments_drop_service_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe Deployments::OlderDeploymentsDropService do
it 'does not drop an older deployment and tracks the exception' do
expect(Gitlab::ErrorTracking).to receive(:track_exception)
- .with(kind_of(RuntimeError), subject_id: deployment.id, deployment_id: older_deployment.id)
+ .with(kind_of(RuntimeError), subject_id: deployment.id, build_id: older_deployment.deployable_id)
expect { subject }.not_to change { Ci::Build.failed.count }
end
diff --git a/spec/support/database/cross-database-modification-allowlist.yml b/spec/support/database/cross-database-modification-allowlist.yml
index 819a77a697b..288a3bed469 100644
--- a/spec/support/database/cross-database-modification-allowlist.yml
+++ b/spec/support/database/cross-database-modification-allowlist.yml
@@ -1228,6 +1228,7 @@
- "./spec/requests/api/commit_statuses_spec.rb"
- "./spec/requests/api/graphql/ci/runner_spec.rb"
- "./spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb"
+- "./spec/requests/api/graphql/project/issues_spec.rb"
- "./spec/requests/api/graphql/project/merge_request_spec.rb"
- "./spec/requests/api/graphql/project_query_spec.rb"
- "./spec/requests/api/issues/issues_spec.rb"
diff --git a/spec/support/database/cross-join-allowlist.yml b/spec/support/database/cross-join-allowlist.yml
index af5d9b1efb3..8006113ce8c 100644
--- a/spec/support/database/cross-join-allowlist.yml
+++ b/spec/support/database/cross-join-allowlist.yml
@@ -70,8 +70,6 @@
- "./spec/models/ci/job_artifact_spec.rb"
- "./spec/models/ci/pipeline_spec.rb"
- "./spec/models/ci/runner_spec.rb"
-- "./spec/models/deployment_spec.rb"
-- "./spec/models/environment_spec.rb"
- "./spec/models/merge_request_spec.rb"
- "./spec/models/project_spec.rb"
- "./spec/models/user_spec.rb"