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>2020-11-06 21:09:07 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-06 21:09:07 +0300
commitf3db01da507f86cfed412c7d337e3747744cc914 (patch)
tree3862e3ca223038c1390e2d19708ebeeecb040e00 /spec
parenta268b09416c8dc3da3af38933028fa26375b88e0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb16
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb19
-rw-r--r--spec/features/file_uploads/multipart_invalid_uploads_spec.rb6
-rw-r--r--spec/features/merge_requests/user_exports_as_csv_spec.rb31
-rw-r--r--spec/finders/merge_requests_finder_spec.rb81
-rw-r--r--spec/frontend/alerts_settings/alerts_settings_form_new_spec.js24
-rw-r--r--spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js87
-rw-r--r--spec/frontend/alerts_settings/mocks/apollo_mock.js97
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js4
-rw-r--r--spec/frontend/registry/explorer/components/details_page/tags_list_spec.js24
-rw-r--r--spec/frontend/registry/explorer/pages/details_spec.js2
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js4
-rw-r--r--spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb23
-rw-r--r--spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb44
-rw-r--r--spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb30
-rw-r--r--spec/requests/user_sends_malformed_strings_spec.rb10
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb2
17 files changed, 299 insertions, 205 deletions
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 31ce37a0607..d7d1278159b 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -1998,10 +1998,6 @@ RSpec.describe Projects::MergeRequestsController do
describe 'POST export_csv' do
subject { post :export_csv, params: { namespace_id: project.namespace, project_id: project } }
- before do
- stub_feature_flags(export_merge_requests_as_csv: project)
- end
-
it 'redirects to the merge request index' do
subject
@@ -2014,17 +2010,5 @@ RSpec.describe Projects::MergeRequestsController do
subject
end
-
- context 'feature is disabled' do
- before do
- stub_feature_flags(export_merge_requests_as_csv: false)
- end
-
- it 'expects a 404 response' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
end
end
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index a47f2285e37..952a78ec79a 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -52,29 +52,20 @@ RSpec.describe 'Dashboard Merge Requests' do
end
context 'merge requests exist' do
- let_it_be(:author_user) { create(:user) }
let(:label) { create(:label) }
let!(:assigned_merge_request) do
create(:merge_request,
assignees: [current_user],
source_project: project,
- author: author_user)
- end
-
- let!(:review_requested_merge_request) do
- create(:merge_request,
- reviewers: [current_user],
- source_branch: 'review',
- source_project: project,
- author: author_user)
+ author: create(:user))
end
let!(:assigned_merge_request_from_fork) do
create(:merge_request,
source_branch: 'markdown', assignees: [current_user],
target_project: public_project, source_project: forked_project,
- author: author_user)
+ author: create(:user))
end
let!(:authored_merge_request) do
@@ -103,7 +94,7 @@ RSpec.describe 'Dashboard Merge Requests' do
create(:merge_request,
source_branch: 'fix',
source_project: project,
- author: author_user)
+ author: create(:user))
end
before do
@@ -120,10 +111,6 @@ RSpec.describe 'Dashboard Merge Requests' do
expect(page).not_to have_content(labeled_merge_request.title)
end
- it 'shows review requested merge requests' do
- expect(page).to have_content(review_requested_merge_request.title)
- end
-
it 'shows authored merge requests', :js do
reset_filters
input_filtered_search("author:=#{current_user.to_reference}")
diff --git a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
index e9e24c12af1..b3ace2e30ff 100644
--- a/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
+++ b/spec/features/file_uploads/multipart_invalid_uploads_spec.rb
@@ -22,13 +22,13 @@ RSpec.describe 'Invalid uploads that must be rejected', :api, :js do
)
end
- RSpec.shared_examples 'rejecting invalid keys' do |key_name:, message: nil|
+ RSpec.shared_examples 'rejecting invalid keys' do |key_name:, message: nil, status: 500|
context "with invalid key #{key_name}" do
let(:body) { { key_name => file, 'package[test][name]' => 'test' } }
it { expect { subject }.not_to change { Packages::Package.nuget.count } }
- it { expect(subject.code).to eq(500) }
+ it { expect(subject.code).to eq(status) }
it { expect(subject.body).to include(message.presence || "invalid field: \"#{key_name}\"") }
end
@@ -45,7 +45,7 @@ RSpec.describe 'Invalid uploads that must be rejected', :api, :js do
# These keys are rejected directly by rack itself.
# The request will not be received by multipart.rb (can't use the 'handling file uploads' shared example)
it_behaves_like 'rejecting invalid keys', key_name: 'x' * 11000, message: 'Puma caught this error: exceeded available parameter key space (RangeError)'
- it_behaves_like 'rejecting invalid keys', key_name: 'package[]test', message: 'Puma caught this error: expected Hash (got Array)'
+ it_behaves_like 'rejecting invalid keys', key_name: 'package[]test', status: 400, message: 'Bad Request'
it_behaves_like 'handling file uploads', 'by rejecting uploads with an invalid key'
end
diff --git a/spec/features/merge_requests/user_exports_as_csv_spec.rb b/spec/features/merge_requests/user_exports_as_csv_spec.rb
index 63ed1cb5231..a86ff9d7335 100644
--- a/spec/features/merge_requests/user_exports_as_csv_spec.rb
+++ b/spec/features/merge_requests/user_exports_as_csv_spec.rb
@@ -9,38 +9,23 @@ RSpec.describe 'Merge Requests > Exports as CSV', :js do
before do
sign_in(user)
+ visit(project_merge_requests_path(project))
end
subject { page.find('.nav-controls') }
- context 'feature is not enabled' do
- before do
- stub_feature_flags(export_merge_requests_as_csv: false)
- visit(project_merge_requests_path(project))
- end
-
- it { is_expected.not_to have_button('Export as CSV') }
- end
+ it { is_expected.to have_button('Export as CSV') }
- context 'feature is enabled for a project' do
+ context 'button is clicked' do
before do
- stub_feature_flags(export_merge_requests_as_csv: project)
- visit(project_merge_requests_path(project))
+ click_button('Export as CSV')
end
- it { is_expected.to have_button('Export as CSV') }
-
- context 'button is clicked' do
- before do
- click_button('Export as CSV')
- end
-
- it 'shows a success message' do
- click_link('Export merge requests')
+ it 'shows a success message' do
+ click_link('Export merge requests')
- expect(page).to have_content 'Your CSV export has started.'
- expect(page).to have_content "It will be emailed to #{user.email} when complete"
- end
+ expect(page).to have_content 'Your CSV export has started.'
+ expect(page).to have_content "It will be emailed to #{user.email} when complete"
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 3ab1b26d71d..68958e37001 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -333,8 +333,6 @@ RSpec.describe MergeRequestsFinder do
end
context 'assignee filtering' do
- let_it_be(:user3) { create(:user) }
-
let(:issuables) { described_class.new(user, params).execute }
it_behaves_like 'assignee ID filter' do
@@ -353,6 +351,7 @@ RSpec.describe MergeRequestsFinder do
merge_request3.assignees = [user2, user3]
end
+ let_it_be(:user3) { create(:user) }
let(:params) { { assignee_username: [user2.username, user3.username] } }
let(:expected_issuables) { [merge_request3] }
end
@@ -367,6 +366,7 @@ RSpec.describe MergeRequestsFinder do
end
it_behaves_like 'no assignee filter' do
+ let_it_be(:user3) { create(:user) }
let(:expected_issuables) { [merge_request4, merge_request5] }
end
@@ -374,54 +374,30 @@ RSpec.describe MergeRequestsFinder do
let(:expected_issuables) { [merge_request1, merge_request2, merge_request3] }
end
- context 'with just reviewers' do
- it_behaves_like 'assignee username filter' do
- before do
- merge_request4.reviewers = [user3]
- merge_request4.assignees = []
- end
+ context 'filtering by group milestone' do
+ let(:group_milestone) { create(:milestone, group: group) }
- let(:params) { { assignee_username: [user3.username] } }
- let(:expected_issuables) { [merge_request4] }
+ before do
+ merge_request1.update!(milestone: group_milestone)
+ merge_request2.update!(milestone: group_milestone)
end
- end
- context 'with an additional reviewer' do
- it_behaves_like 'assignee username filter' do
- before do
- merge_request3.assignees = [user3]
- merge_request4.reviewers = [user3]
- end
+ it 'returns merge requests assigned to that group milestone' do
+ params = { milestone_title: group_milestone.title }
- let(:params) { { assignee_username: [user3.username] } }
- let(:expected_issuables) { [merge_request3, merge_request4] }
- end
- end
- end
-
- context 'filtering by group milestone' do
- let(:group_milestone) { create(:milestone, group: group) }
-
- before do
- merge_request1.update!(milestone: group_milestone)
- merge_request2.update!(milestone: group_milestone)
- end
-
- it 'returns merge requests assigned to that group milestone' do
- params = { milestone_title: group_milestone.title }
-
- merge_requests = described_class.new(user, params).execute
+ merge_requests = described_class.new(user, params).execute
- expect(merge_requests).to contain_exactly(merge_request1, merge_request2)
- end
+ expect(merge_requests).to contain_exactly(merge_request1, merge_request2)
+ end
- context 'using NOT' do
- let(:params) { { not: { milestone_title: group_milestone.title } } }
+ context 'using NOT' do
+ let(:params) { { not: { milestone_title: group_milestone.title } } }
- it 'returns MRs not assigned to that group milestone' do
- merge_requests = described_class.new(user, params).execute
+ it 'returns MRs not assigned to that group milestone' do
+ merge_requests = described_class.new(user, params).execute
- expect(merge_requests).to contain_exactly(merge_request3, merge_request4, merge_request5)
+ expect(merge_requests).to contain_exactly(merge_request3, merge_request4, merge_request5)
+ end
end
end
end
@@ -587,27 +563,6 @@ RSpec.describe MergeRequestsFinder do
expect(mrs).to eq([mr2])
end
end
-
- it 'does not raise any exception with complex filters' do
- # available filters from MergeRequest dashboard UI
- params = {
- project_id: project1.id,
- scope: 'authored',
- state: 'opened',
- author_username: user.username,
- assignee_username: user.username,
- approver_usernames: [user.username],
- approved_by_usernames: [user.username],
- milestone_title: 'none',
- release_tag: 'none',
- label_names: 'none',
- my_reaction_emoji: 'none',
- draft: 'no'
- }
-
- merge_requests = described_class.new(user, params).execute
- expect { merge_requests.load }.not_to raise_error
- end
end
describe '#row_count', :request_store do
diff --git a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js
index 8d14babf4af..59238e40686 100644
--- a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js
+++ b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js
@@ -128,18 +128,18 @@ describe('AlertsSettingsFormNew', () => {
it('allows for update-integration with the correct form values for HTTP', async () => {
createComponent({
+ data: {
+ selectedIntegration: typeSet.http,
+ },
props: {
- currentIntegration: { id: '1' },
+ currentIntegration: { id: '1', name: 'Test integration pre' },
loading: false,
},
});
- const options = findSelect().findAll('option');
- await options.at(1).setSelected();
-
await findFormFields()
.at(0)
- .setValue('Test integration');
+ .setValue('Test integration post');
await findFormToggle().trigger('click');
await wrapper.vm.$nextTick();
@@ -153,27 +153,27 @@ describe('AlertsSettingsFormNew', () => {
expect(wrapper.emitted('update-integration')).toBeTruthy();
expect(wrapper.emitted('update-integration')[0]).toEqual([
- { type: typeSet.http, variables: { name: 'Test integration', active: true } },
+ { type: typeSet.http, variables: { name: 'Test integration post', active: true } },
]);
});
it('allows for update-integration with the correct form values for PROMETHEUS', async () => {
createComponent({
+ data: {
+ selectedIntegration: typeSet.prometheus,
+ },
props: {
- currentIntegration: { id: '1' },
+ currentIntegration: { id: '1', apiUrl: 'https://test-pre.com' },
loading: false,
},
});
- const options = findSelect().findAll('option');
- await options.at(2).setSelected();
-
await findFormFields()
.at(0)
.setValue('Test integration');
await findFormFields()
.at(1)
- .setValue('https://test.com');
+ .setValue('https://test-post.com');
await findFormToggle().trigger('click');
await wrapper.vm.$nextTick();
@@ -187,7 +187,7 @@ describe('AlertsSettingsFormNew', () => {
expect(wrapper.emitted('update-integration')).toBeTruthy();
expect(wrapper.emitted('update-integration')[0]).toEqual([
- { type: typeSet.prometheus, variables: { apiUrl: 'https://test.com', active: true } },
+ { type: typeSet.prometheus, variables: { apiUrl: 'https://test-post.com', active: true } },
]);
});
});
diff --git a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js
index 5fa21d01340..e2e7034940d 100644
--- a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js
+++ b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js
@@ -1,13 +1,17 @@
-import { mount } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import { mount, createLocalVue } from '@vue/test-utils';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
import { GlLoadingIcon } from '@gitlab/ui';
import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue';
import AlertsSettingsFormOld from '~/alerts_settings/components/alerts_settings_form_old.vue';
import AlertsSettingsFormNew from '~/alerts_settings/components/alerts_settings_form_new.vue';
import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue';
+import getIntegrationsQuery from '~/alerts_settings/graphql/queries/get_integrations.query.graphql';
import createHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
import createPrometheusIntegrationMutation from '~/alerts_settings/graphql/mutations/create_prometheus_integration.mutation.graphql';
import updateHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
import updatePrometheusIntegrationMutation from '~/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql';
+import destroyHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql';
import resetHttpTokenMutation from '~/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql';
import resetPrometheusTokenMutation from '~/alerts_settings/graphql/mutations/reset_prometheus_token.mutation.graphql';
import { typeSet } from '~/alerts_settings/constants';
@@ -20,16 +24,34 @@ import {
createPrometheusVariables,
updatePrometheusVariables,
ID,
+ errorMsg,
+ getIntegrationsQueryResponse,
+ destroyIntegrationResponse,
+ integrationToDestroy,
+ destroyIntegrationResponseWithErrors,
} from './mocks/apollo_mock';
jest.mock('~/flash');
+const localVue = createLocalVue();
+
describe('AlertsSettingsWrapper', () => {
let wrapper;
+ let fakeApollo;
+ let destroyIntegrationHandler;
const findLoader = () => wrapper.find(IntegrationsList).find(GlLoadingIcon);
const findIntegrations = () => wrapper.find(IntegrationsList).findAll('table tbody tr');
+ async function destroyHttpIntegration(localWrapper) {
+ await jest.runOnlyPendingTimers();
+ await localWrapper.vm.$nextTick();
+
+ localWrapper
+ .find(IntegrationsList)
+ .vm.$emit('delete-integration', { id: integrationToDestroy.id });
+ }
+
const createComponent = ({ data = {}, provide = {}, loading = false } = {}) => {
wrapper = mount(AlertsSettingsWrapper, {
data() {
@@ -54,6 +76,29 @@ describe('AlertsSettingsWrapper', () => {
});
};
+ function createComponentWithApollo({
+ destroyHandler = jest.fn().mockResolvedValue(destroyIntegrationResponse),
+ } = {}) {
+ localVue.use(VueApollo);
+ destroyIntegrationHandler = destroyHandler;
+
+ const requestHandlers = [
+ [getIntegrationsQuery, jest.fn().mockResolvedValue(getIntegrationsQueryResponse)],
+ [destroyHttpIntegrationMutation, destroyIntegrationHandler],
+ ];
+
+ fakeApollo = createMockApollo(requestHandlers);
+
+ wrapper = mount(AlertsSettingsWrapper, {
+ localVue,
+ apolloProvider: fakeApollo,
+ provide: {
+ ...defaultAlertSettingsConfig,
+ glFeatures: { httpIntegrationsList: true },
+ },
+ });
+ }
+
afterEach(() => {
if (wrapper) {
wrapper.destroy();
@@ -243,7 +288,6 @@ describe('AlertsSettingsWrapper', () => {
});
it('shows error alert when integration creation fails ', async () => {
- const errorMsg = 'Something went wrong';
createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
@@ -259,7 +303,6 @@ describe('AlertsSettingsWrapper', () => {
});
it('shows error alert when integration token reset fails ', () => {
- const errorMsg = 'Something went wrong';
createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
@@ -276,7 +319,6 @@ describe('AlertsSettingsWrapper', () => {
});
it('shows error alert when integration update fails ', () => {
- const errorMsg = 'Something went wrong';
createComponent({
data: { integrations: { list: mockIntegrations }, currentIntegration: mockIntegrations[0] },
provide: { glFeatures: { httpIntegrationsList: true } },
@@ -292,4 +334,41 @@ describe('AlertsSettingsWrapper', () => {
});
});
});
+
+ describe('with mocked Apollo client', () => {
+ it('has a selection of integrations loaded via the getIntegrationsQuery', async () => {
+ createComponentWithApollo();
+
+ await jest.runOnlyPendingTimers();
+ await wrapper.vm.$nextTick();
+
+ expect(findIntegrations()).toHaveLength(4);
+ });
+
+ it('calls a mutation with correct parameters and destroys a integration', async () => {
+ createComponentWithApollo();
+
+ await destroyHttpIntegration(wrapper);
+
+ expect(destroyIntegrationHandler).toHaveBeenCalled();
+
+ await wrapper.vm.$nextTick();
+
+ expect(findIntegrations()).toHaveLength(3);
+ });
+
+ it('displays flash if mutation had a recoverable error', async () => {
+ createComponentWithApollo({
+ destroyHandler: jest.fn().mockResolvedValue(destroyIntegrationResponseWithErrors),
+ });
+
+ await destroyHttpIntegration(wrapper);
+
+ await wrapper.vm.$nextTick(); // kick off the DOM update
+ await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
+ await wrapper.vm.$nextTick(); // kick off the DOM update for flash
+
+ expect(createFlash).toHaveBeenCalledWith({ message: 'Houston, we have a problem' });
+ });
+ });
});
diff --git a/spec/frontend/alerts_settings/mocks/apollo_mock.js b/spec/frontend/alerts_settings/mocks/apollo_mock.js
index d4cf0627c66..e0eba1e8421 100644
--- a/spec/frontend/alerts_settings/mocks/apollo_mock.js
+++ b/spec/frontend/alerts_settings/mocks/apollo_mock.js
@@ -1,5 +1,6 @@
const projectPath = '';
export const ID = 'gid://gitlab/AlertManagement::HttpIntegration/7';
+export const errorMsg = 'Something went wrong';
export const createHttpVariables = {
name: 'Test Pre',
@@ -24,3 +25,99 @@ export const updatePrometheusVariables = {
active: true,
id: ID,
};
+
+export const getIntegrationsQueryResponse = {
+ data: {
+ project: {
+ alertManagementIntegrations: {
+ nodes: [
+ {
+ id: '37',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 5',
+ url:
+ 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-5/d4875758e67334f3.json',
+ token: '89eb01df471d990ff5162a1c640408cf',
+ apiUrl: null,
+ },
+ {
+ id: '41',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 9999',
+ url:
+ 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-9999/b78a566e1776cfc2.json',
+ token: 'f7579aa03844e07af3b1f0fca3f79f81',
+ apiUrl: null,
+ },
+ {
+ id: '40',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 6',
+ url:
+ 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-6/3e828ae28a240222.json',
+ token: '6536102a607a5dd74fcdde921f2349ee',
+ apiUrl: null,
+ },
+ {
+ id: '12',
+ type: 'PROMETHEUS',
+ active: false,
+ name: 'Prometheus',
+ url: 'http://127.0.0.1:3000/h5bp/html5-boilerplate/prometheus/alerts/notify.json',
+ token: '256f687c6225aa5d6ee50c3d68120c4c',
+ apiUrl: 'https://localhost.ieeeesassadasasa',
+ },
+ ],
+ },
+ },
+ },
+};
+
+export const integrationToDestroy = {
+ id: '37',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 5',
+ url: 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-5/d4875758e67334f3.json',
+ token: '89eb01df471d990ff5162a1c640408cf',
+ apiUrl: null,
+};
+
+export const destroyIntegrationResponse = {
+ data: {
+ httpIntegrationDestroy: {
+ errors: [],
+ integration: {
+ id: '37',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 5',
+ url:
+ 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-5/d4875758e67334f3.json',
+ token: '89eb01df471d990ff5162a1c640408cf',
+ apiUrl: null,
+ },
+ },
+ },
+};
+
+export const destroyIntegrationResponseWithErrors = {
+ data: {
+ httpIntegrationDestroy: {
+ errors: ['Houston, we have a problem'],
+ integration: {
+ id: '37',
+ type: 'HTTP',
+ active: true,
+ name: 'Test 5',
+ url:
+ 'http://127.0.0.1:3000/h5bp/html5-boilerplate/alerts/notify/test-5/d4875758e67334f3.json',
+ token: '89eb01df471d990ff5162a1c640408cf',
+ apiUrl: null,
+ },
+ },
+ },
+};
diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
index ef22979ca7d..3276ef911e3 100644
--- a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js
@@ -22,7 +22,7 @@ describe('tags list row', () => {
let wrapper;
const [tag] = [...tagsListResponse.data];
- const defaultProps = { tag, isDesktop: true, index: 0 };
+ const defaultProps = { tag, isMobile: false, index: 0 };
const findCheckbox = () => wrapper.find(GlFormCheckbox);
const findName = () => wrapper.find('[data-testid="name"]');
@@ -114,7 +114,7 @@ describe('tags list row', () => {
});
it('on mobile has mw-s class', () => {
- mountComponent({ ...defaultProps, isDesktop: false });
+ mountComponent({ ...defaultProps, isMobile: true });
expect(findName().classes('mw-s')).toBe(true);
});
diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
index 401202026bb..ebeaa8ff870 100644
--- a/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
+++ b/spec/frontend/registry/explorer/components/details_page/tags_list_spec.js
@@ -14,7 +14,7 @@ describe('Tags List', () => {
const findDeleteButton = () => wrapper.find(GlButton);
const findListTitle = () => wrapper.find('[data-testid="list-title"]');
- const mountComponent = (propsData = { tags, isDesktop: true }) => {
+ const mountComponent = (propsData = { tags, isMobile: false }) => {
wrapper = shallowMount(component, {
propsData,
});
@@ -41,15 +41,15 @@ describe('Tags List', () => {
describe('delete button', () => {
it.each`
- inputTags | isDesktop | isVisible
- ${tags} | ${true} | ${true}
- ${tags} | ${false} | ${false}
- ${readOnlyTags} | ${true} | ${false}
- ${readOnlyTags} | ${false} | ${false}
+ inputTags | isMobile | isVisible
+ ${tags} | ${false} | ${true}
+ ${tags} | ${true} | ${false}
+ ${readOnlyTags} | ${false} | ${false}
+ ${readOnlyTags} | ${true} | ${false}
`(
- 'is $isVisible that delete button exists when tags is $inputTags and isDesktop is $isDesktop',
- ({ inputTags, isDesktop, isVisible }) => {
- mountComponent({ tags: inputTags, isDesktop });
+ 'is $isVisible that delete button exists when tags is $inputTags and isMobile is $isMobile',
+ ({ inputTags, isMobile, isVisible }) => {
+ mountComponent({ tags: inputTags, isMobile });
expect(findDeleteButton().exists()).toBe(isVisible);
},
@@ -110,12 +110,6 @@ describe('Tags List', () => {
expect(rows.at(0).attributes()).toMatchObject({
first: 'true',
- isdesktop: 'true',
- });
-
- // The list has only two tags and for some reasons .at(-1) does not work
- expect(rows.at(1).attributes()).toMatchObject({
- isdesktop: 'true',
});
});
diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js
index 86b52c4f06a..372875914a5 100644
--- a/spec/frontend/registry/explorer/pages/details_spec.js
+++ b/spec/frontend/registry/explorer/pages/details_spec.js
@@ -124,7 +124,7 @@ describe('Details Page', () => {
it('has the correct props bound', () => {
expect(findTagsList().props()).toMatchObject({
- isDesktop: true,
+ isMobile: false,
tags: store.state.tags,
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
index 5c7e6a87c16..56832f82b05 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem } from '@gitlab/ui';
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
const commits = [
@@ -39,7 +39,7 @@ describe('Commits message dropdown component', () => {
wrapper.destroy();
});
- const findDropdownElements = () => wrapper.findAll(GlDeprecatedDropdownItem);
+ const findDropdownElements = () => wrapper.findAll(GlDropdownItem);
const findFirstDropdownElement = () => findDropdownElements().at(0);
it('should have 3 elements in dropdown list', () => {
diff --git a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
index cf1f00bc176..7ae33346388 100644
--- a/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
+++ b/spec/lib/gitlab/graphql/loaders/batch_model_loader_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
RSpec.describe Gitlab::Graphql::Loaders::BatchModelLoader do
describe '#find' do
- let(:issue) { create(:issue) }
- let(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:user) { create(:user) }
it 'finds a model by id' do
issue_result = described_class.new(Issue, issue.id).find
@@ -16,15 +17,25 @@ RSpec.describe Gitlab::Graphql::Loaders::BatchModelLoader do
end
it 'only queries once per model' do
- other_user = create(:user)
- user
- issue
-
expect do
[described_class.new(User, other_user.id).find,
described_class.new(User, user.id).find,
described_class.new(Issue, issue.id).find].map(&:sync)
end.not_to exceed_query_limit(2)
end
+
+ it 'does not force values unnecessarily' do
+ expect do
+ a = described_class.new(User, user.id).find
+ b = described_class.new(Issue, issue.id).find
+
+ b.sync
+
+ c = described_class.new(User, other_user.id).find
+
+ a.sync
+ c.sync
+ end.not_to exceed_query_limit(2)
+ end
end
end
diff --git a/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb
index 5ed1580fa8d..fec273ecafd 100644
--- a/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb
+++ b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb
@@ -4,6 +4,8 @@ require 'spec_helper'
require "rack/test"
RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
+ include GitHttpHelpers
+
let(:null_byte) { "\u0000" }
let(:escaped_null_byte) { "%00" }
let(:invalid_string) { "mal\xC0formed" }
@@ -57,6 +59,22 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
end
end
+ context 'in authorization headers' do
+ let(:problematic_input) { null_byte }
+
+ it 'rejects problematic input in the password' do
+ env = env_for.merge(auth_env("username", "password#{problematic_input}encoded", nil))
+
+ expect(subject.call(env)).to eq error_400
+ end
+
+ it 'rejects problematic input in the password' do
+ env = env_for.merge(auth_env("username#{problematic_input}", "password#{problematic_input}encoded", nil))
+
+ expect(subject.call(env)).to eq error_400
+ end
+ end
+
context 'in params' do
shared_examples_for 'checks params' do
it 'rejects bad params in a top level param' do
@@ -86,24 +104,24 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
expect(subject.call(env)).to eq error_400
end
+ end
+
+ context 'with null byte' do
+ let(:problematic_input) { null_byte }
+
+ it_behaves_like 'checks params'
it "gives up and does not reject too deeply nested params" do
env = env_for(name: [
- {
- inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{problematic_input} bad" }] }
- }
- ])
+ {
+ inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{problematic_input} bad" }] }
+ }
+ ])
expect(subject.call(env)).not_to eq error_400
end
end
- context 'with null byte' do
- it_behaves_like 'checks params' do
- let(:problematic_input) { null_byte }
- end
- end
-
context 'with malformed strings' do
it_behaves_like 'checks params' do
let(:problematic_input) { invalid_string }
@@ -124,4 +142,10 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
expect(subject.call(env)).not_to eq error_400
end
end
+
+ it 'does not modify the env' do
+ env = env_for
+
+ expect { subject.call(env) }.not_to change { env }
+ end
end
diff --git a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
index c86b3a01d1e..803eff05efe 100644
--- a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
@@ -168,36 +168,6 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
end
end
- context 'for Issue added to epic actions' do
- it_behaves_like 'a tracked issue edit event' do
- let(:action) { described_class::ISSUE_ADDED_TO_EPIC}
-
- def track_action(params)
- described_class.track_issue_added_to_epic_action(**params)
- end
- end
- end
-
- context 'for Issue removed from epic actions' do
- it_behaves_like 'a tracked issue edit event' do
- let(:action) { described_class::ISSUE_REMOVED_FROM_EPIC}
-
- def track_action(params)
- described_class.track_issue_removed_from_epic_action(**params)
- end
- end
- end
-
- context 'for Issue changed epic actions' do
- it_behaves_like 'a tracked issue edit event' do
- let(:action) { described_class::ISSUE_CHANGED_EPIC}
-
- def track_action(params)
- described_class.track_issue_changed_epic_action(**params)
- end
- end
- end
-
context 'for Issue designs added actions' do
it_behaves_like 'a tracked issue edit event' do
let(:action) { described_class::ISSUE_DESIGNS_ADDED }
diff --git a/spec/requests/user_sends_malformed_strings_spec.rb b/spec/requests/user_sends_malformed_strings_spec.rb
index b6eda9159bc..da533606be5 100644
--- a/spec/requests/user_sends_malformed_strings_spec.rb
+++ b/spec/requests/user_sends_malformed_strings_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe 'User sends malformed strings as params' do
+RSpec.describe 'User sends malformed strings' do
+ include GitHttpHelpers
+
let(:null_byte) { "\u0000" }
let(:invalid_string) { "mal\xC0formed" }
@@ -17,4 +19,10 @@ RSpec.describe 'User sends malformed strings as params' do
expect(response).to have_gitlab_http_status(:bad_request)
end
+
+ it 'raises a 400 error with null bytes in the auth headers' do
+ clone_get("project/path", user: "hello#{null_byte}", password: "nothing to see")
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
index 24ab64b20f5..facb4e2016d 100644
--- a/spec/views/projects/settings/operations/show.html.haml_spec.rb
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'projects/settings/operations/show' do
end
before_all do
- project.add_reporter(user)
+ project.add_maintainer(user)
end
before do