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-05-12 12:08:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-12 12:08:08 +0300
commit71d34aac9a0fae0507c265929767422391816b01 (patch)
treededb769442c9576e2f44bf3c500b013beb9604d9 /spec
parent90726a8ccc9df6d9b5ff4f5e1eb31d015c1db8e2 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/__helpers__/init_vue_mr_page_helper.js18
-rw-r--r--spec/frontend/__helpers__/matchers/to_have_sprite_icon.js2
-rw-r--r--spec/frontend/access_tokens/index_spec.js2
-rw-r--r--spec/frontend/admin/users/index_spec.js8
-rw-r--r--spec/frontend/authentication/two_factor_auth/index_spec.js4
-rw-r--r--spec/frontend/blob/components/table_contents_spec.js4
-rw-r--r--spec/frontend/blob/viewer/index_spec.js6
-rw-r--r--spec/frontend/cascading_settings/components/lock_popovers_spec.js10
-rw-r--r--spec/frontend/code_navigation/store/actions_spec.js12
-rw-r--r--spec/frontend/confirm_modal_spec.js6
-rw-r--r--spec/frontend/helpers/startup_css_helper_spec.js7
-rw-r--r--spec/frontend/issues/create_merge_request_dropdown_spec.js4
-rw-r--r--spec/frontend/labels/delete_label_modal_spec.js6
-rw-r--r--spec/frontend/lazy_loader_spec.js4
-rw-r--r--spec/frontend/members/index_spec.js2
-rw-r--r--spec/frontend/members/utils_spec.js2
-rw-r--r--spec/frontend/notebook/cells/markdown_spec.js4
-rw-r--r--spec/frontend/notes/stores/actions_spec.js10
-rw-r--r--spec/frontend/performance_bar/index_spec.js10
-rw-r--r--spec/frontend/pipeline_editor/components/file-tree/container_spec.js7
-rw-r--r--spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js22
-rw-r--r--spec/frontend/pipeline_editor/mock_data.js1
-rw-r--r--spec/frontend/search_autocomplete_spec.js2
-rw-r--r--spec/frontend/user_popovers_spec.js2
-rw-r--r--spec/frontend/users_select/test_helper.js8
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js4
-rw-r--r--spec/frontend/vue_mr_widget/mr_widget_options_spec.js2
-rw-r--r--spec/frontend_integration/ide/helpers/ide_helper.js4
-rw-r--r--spec/helpers/ci/pipeline_editor_helper_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb12
-rw-r--r--spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb26
-rw-r--r--spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb8
-rw-r--r--spec/lib/gitlab/auth/otp/strategies/forti_authenticator/manual_otp_spec.rb (renamed from spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb)2
-rw-r--r--spec/lib/gitlab/auth/otp/strategies/forti_authenticator/push_otp_spec.rb65
-rw-r--r--spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb35
-rw-r--r--spec/migrations/20220428133724_schedule_expire_o_auth_tokens_spec.rb31
-rw-r--r--spec/migrations/20220505174658_update_index_on_alerts_to_exclude_null_fingerprints_spec.rb24
-rw-r--r--spec/models/alert_management/alert_spec.rb4
-rw-r--r--spec/requests/api/internal/base_spec.rb83
-rw-r--r--spec/services/alert_management/alerts/update_service_spec.rb45
-rw-r--r--spec/services/users/validate_manual_otp_service_spec.rb (renamed from spec/services/users/validate_otp_service_spec.rb)27
-rw-r--r--spec/services/users/validate_push_otp_service_spec.rb45
43 files changed, 461 insertions, 123 deletions
diff --git a/spec/frontend/__helpers__/init_vue_mr_page_helper.js b/spec/frontend/__helpers__/init_vue_mr_page_helper.js
index 6b719a32480..ee01e9e6268 100644
--- a/spec/frontend/__helpers__/init_vue_mr_page_helper.js
+++ b/spec/frontend/__helpers__/init_vue_mr_page_helper.js
@@ -13,16 +13,16 @@ export default function initVueMRPage() {
const diffsAppProjectPath = 'testproject';
const mrEl = document.createElement('div');
mrEl.className = 'merge-request fixture-mr';
- mrEl.dataset.mrAction = 'diffs';
+ mrEl.setAttribute('data-mr-action', 'diffs');
mrTestEl.appendChild(mrEl);
const mrDiscussionsEl = document.createElement('div');
mrDiscussionsEl.id = 'js-vue-mr-discussions';
- mrDiscussionsEl.dataset.currentUserData = JSON.stringify(userDataMock);
- mrDiscussionsEl.dataset.noteableData = JSON.stringify(noteableDataMock);
- mrDiscussionsEl.dataset.notesData = JSON.stringify(notesDataMock);
- mrDiscussionsEl.dataset.noteableType = 'merge-request';
- mrDiscussionsEl.dataset.isLocked = 'false';
+ mrDiscussionsEl.setAttribute('data-current-user-data', JSON.stringify(userDataMock));
+ mrDiscussionsEl.setAttribute('data-noteable-data', JSON.stringify(noteableDataMock));
+ mrDiscussionsEl.setAttribute('data-notes-data', JSON.stringify(notesDataMock));
+ mrDiscussionsEl.setAttribute('data-noteable-type', 'merge-request');
+ mrDiscussionsEl.setAttribute('data-is-locked', 'false');
mrTestEl.appendChild(mrDiscussionsEl);
const discussionCounterEl = document.createElement('div');
@@ -31,9 +31,9 @@ export default function initVueMRPage() {
const diffsAppEl = document.createElement('div');
diffsAppEl.id = 'js-diffs-app';
- diffsAppEl.dataset.endpoint = diffsAppEndpoint;
- diffsAppEl.dataset.projectPath = diffsAppProjectPath;
- diffsAppEl.dataset.currentUserData = JSON.stringify(userDataMock);
+ diffsAppEl.setAttribute('data-endpoint', diffsAppEndpoint);
+ diffsAppEl.setAttribute('data-project-path', diffsAppProjectPath);
+ diffsAppEl.setAttribute('data-current-user-data', JSON.stringify(userDataMock));
mrTestEl.appendChild(diffsAppEl);
const mock = new MockAdapter(axios);
diff --git a/spec/frontend/__helpers__/matchers/to_have_sprite_icon.js b/spec/frontend/__helpers__/matchers/to_have_sprite_icon.js
index 45b9c31c4db..bce9d93bea8 100644
--- a/spec/frontend/__helpers__/matchers/to_have_sprite_icon.js
+++ b/spec/frontend/__helpers__/matchers/to_have_sprite_icon.js
@@ -9,7 +9,7 @@ export const toHaveSpriteIcon = (element, iconName) => {
const iconReferences = [].slice.apply(element.querySelectorAll('svg use'));
const matchingIcon = iconReferences.find(
- (reference) => reference.parentNode.dataset.testid === `${iconName}-icon`,
+ (reference) => reference.parentNode.getAttribute('data-testid') === `${iconName}-icon`,
);
const pass = Boolean(matchingIcon);
diff --git a/spec/frontend/access_tokens/index_spec.js b/spec/frontend/access_tokens/index_spec.js
index 5f0a7dfc775..1d8ac7cec25 100644
--- a/spec/frontend/access_tokens/index_spec.js
+++ b/spec/frontend/access_tokens/index_spec.js
@@ -39,7 +39,7 @@ describe('access tokens', () => {
const input = document.createElement('input');
input.setAttribute('name', nameAttribute);
- input.dataset.jsName = fieldName;
+ input.setAttribute('data-js-name', fieldName);
input.setAttribute('id', idAttribute);
input.setAttribute('placeholder', 'Foo bar');
input.setAttribute('value', '1,2');
diff --git a/spec/frontend/admin/users/index_spec.js b/spec/frontend/admin/users/index_spec.js
index 961fa96acdd..06dbadd6d3d 100644
--- a/spec/frontend/admin/users/index_spec.js
+++ b/spec/frontend/admin/users/index_spec.js
@@ -12,8 +12,8 @@ describe('initAdminUsersApp', () => {
beforeEach(() => {
el = document.createElement('div');
- el.dataset.users = JSON.stringify(users);
- el.dataset.paths = JSON.stringify(paths);
+ el.setAttribute('data-users', JSON.stringify(users));
+ el.setAttribute('data-paths', JSON.stringify(paths));
wrapper = createWrapper(initAdminUsersApp(el));
});
@@ -40,8 +40,8 @@ describe('initAdminUserActions', () => {
beforeEach(() => {
el = document.createElement('div');
- el.dataset.user = JSON.stringify(user);
- el.dataset.paths = JSON.stringify(paths);
+ el.setAttribute('data-user', JSON.stringify(user));
+ el.setAttribute('data-paths', JSON.stringify(paths));
wrapper = createWrapper(initAdminUserActions(el));
});
diff --git a/spec/frontend/authentication/two_factor_auth/index_spec.js b/spec/frontend/authentication/two_factor_auth/index_spec.js
index f9a6b2df662..0ff9d60f409 100644
--- a/spec/frontend/authentication/two_factor_auth/index_spec.js
+++ b/spec/frontend/authentication/two_factor_auth/index_spec.js
@@ -15,8 +15,8 @@ describe('initRecoveryCodes', () => {
beforeEach(() => {
el = document.createElement('div');
el.setAttribute('class', 'js-2fa-recovery-codes');
- el.dataset.codes = codesJsonString;
- el.dataset.profileAccountPath = profileAccountPath;
+ el.setAttribute('data-codes', codesJsonString);
+ el.setAttribute('data-profile-account-path', profileAccountPath);
document.body.appendChild(el);
wrapper = createWrapper(initRecoveryCodes());
diff --git a/spec/frontend/blob/components/table_contents_spec.js b/spec/frontend/blob/components/table_contents_spec.js
index abb69a0be48..ade35d39b4f 100644
--- a/spec/frontend/blob/components/table_contents_spec.js
+++ b/spec/frontend/blob/components/table_contents_spec.js
@@ -10,7 +10,7 @@ function createComponent() {
}
async function setLoaded(loaded) {
- document.querySelector('.blob-viewer').dataset.loaded = loaded;
+ document.querySelector('.blob-viewer').setAttribute('data-loaded', loaded);
await nextTick();
}
@@ -51,7 +51,7 @@ describe('Markdown table of contents component', () => {
it('does not show dropdown when viewing non-rich content', async () => {
createComponent();
- document.querySelector('.blob-viewer').dataset.type = 'simple';
+ document.querySelector('.blob-viewer').setAttribute('data-type', 'simple');
await setLoaded(true);
diff --git a/spec/frontend/blob/viewer/index_spec.js b/spec/frontend/blob/viewer/index_spec.js
index 94422746fa7..fe55a537b89 100644
--- a/spec/frontend/blob/viewer/index_spec.js
+++ b/spec/frontend/blob/viewer/index_spec.js
@@ -77,9 +77,9 @@ describe('Blob viewer', () => {
return asyncClick()
.then(() => asyncClick())
.then(() => {
- expect(document.querySelector('.blob-viewer[data-type="simple"]').dataset.loaded).toBe(
- 'true',
- );
+ expect(
+ document.querySelector('.blob-viewer[data-type="simple"]').getAttribute('data-loaded'),
+ ).toBe('true');
});
});
diff --git a/spec/frontend/cascading_settings/components/lock_popovers_spec.js b/spec/frontend/cascading_settings/components/lock_popovers_spec.js
index 182e3c1c8ff..585e6ac505b 100644
--- a/spec/frontend/cascading_settings/components/lock_popovers_spec.js
+++ b/spec/frontend/cascading_settings/components/lock_popovers_spec.js
@@ -21,12 +21,12 @@ describe('LockPopovers', () => {
};
if (lockedByApplicationSetting) {
- popoverMountEl.dataset.popoverData = JSON.stringify(popoverData);
+ popoverMountEl.setAttribute('data-popover-data', JSON.stringify(popoverData));
} else if (lockedByAncestor) {
- popoverMountEl.dataset.popoverData = JSON.stringify({
- ...popoverData,
- ancestor_namespace: mockNamespace,
- });
+ popoverMountEl.setAttribute(
+ 'data-popover-data',
+ JSON.stringify({ ...popoverData, ancestor_namespace: mockNamespace }),
+ );
}
document.body.appendChild(popoverMountEl);
diff --git a/spec/frontend/code_navigation/store/actions_spec.js b/spec/frontend/code_navigation/store/actions_spec.js
index a734fd44403..c26416aca94 100644
--- a/spec/frontend/code_navigation/store/actions_spec.js
+++ b/spec/frontend/code_navigation/store/actions_spec.js
@@ -190,8 +190,8 @@ describe('Code navigation actions', () => {
it('commits SET_CURRENT_DEFINITION with LSIF data', () => {
target.classList.add('js-code-navigation');
- target.dataset.lineIndex = '0';
- target.dataset.charIndex = '0';
+ target.setAttribute('data-line-index', '0');
+ target.setAttribute('data-char-index', '0');
return testAction(
actions.showDefinition,
@@ -213,8 +213,8 @@ describe('Code navigation actions', () => {
it('adds hll class to target element', () => {
target.classList.add('js-code-navigation');
- target.dataset.lineIndex = '0';
- target.dataset.charIndex = '0';
+ target.setAttribute('data-line-index', '0');
+ target.setAttribute('data-char-index', '0');
return testAction(
actions.showDefinition,
@@ -238,8 +238,8 @@ describe('Code navigation actions', () => {
it('caches current target element', () => {
target.classList.add('js-code-navigation');
- target.dataset.lineIndex = '0';
- target.dataset.charIndex = '0';
+ target.setAttribute('data-line-index', '0');
+ target.setAttribute('data-char-index', '0');
return testAction(
actions.showDefinition,
diff --git a/spec/frontend/confirm_modal_spec.js b/spec/frontend/confirm_modal_spec.js
index 4224fb6be2a..53991349ee5 100644
--- a/spec/frontend/confirm_modal_spec.js
+++ b/spec/frontend/confirm_modal_spec.js
@@ -31,9 +31,9 @@ describe('ConfirmModal', () => {
buttons.forEach((x) => {
const button = document.createElement('button');
button.setAttribute('class', 'js-confirm-modal-button');
- button.dataset.path = x.path;
- button.dataset.method = x.method;
- button.dataset.modalAttributes = JSON.stringify(x.modalAttributes);
+ button.setAttribute('data-path', x.path);
+ button.setAttribute('data-method', x.method);
+ button.setAttribute('data-modal-attributes', JSON.stringify(x.modalAttributes));
button.innerHTML = 'Action';
buttonContainer.appendChild(button);
});
diff --git a/spec/frontend/helpers/startup_css_helper_spec.js b/spec/frontend/helpers/startup_css_helper_spec.js
index dca9faecea7..703bdbd342f 100644
--- a/spec/frontend/helpers/startup_css_helper_spec.js
+++ b/spec/frontend/helpers/startup_css_helper_spec.js
@@ -56,10 +56,9 @@ describe('waitForCSSLoaded', () => {
<link href="two.css" data-startupcss="loading">
`);
const events = waitForCSSLoaded(mockedCallback);
- document.querySelectorAll('[data-startupcss="loading"]').forEach((elem) => {
- // eslint-disable-next-line no-param-reassign
- elem.dataset.startupcss = 'loaded';
- });
+ document
+ .querySelectorAll('[data-startupcss="loading"]')
+ .forEach((elem) => elem.setAttribute('data-startupcss', 'loaded'));
document.dispatchEvent(new CustomEvent('CSSStartupLinkLoaded'));
await events;
diff --git a/spec/frontend/issues/create_merge_request_dropdown_spec.js b/spec/frontend/issues/create_merge_request_dropdown_spec.js
index cb7173c56a8..20b26f5abba 100644
--- a/spec/frontend/issues/create_merge_request_dropdown_spec.js
+++ b/spec/frontend/issues/create_merge_request_dropdown_spec.js
@@ -84,7 +84,7 @@ describe('CreateMergeRequestDropdown', () => {
});
it('enables when can create confidential issue', () => {
- document.querySelector('.js-create-mr').dataset.isConfidential = 'true';
+ document.querySelector('.js-create-mr').setAttribute('data-is-confidential', 'true');
confidentialState.selectedProject = { name: 'test' };
dropdown.enable();
@@ -93,7 +93,7 @@ describe('CreateMergeRequestDropdown', () => {
});
it('does not enable when can not create confidential issue', () => {
- document.querySelector('.js-create-mr').dataset.isConfidential = 'true';
+ document.querySelector('.js-create-mr').setAttribute('data-is-confidential', 'true');
dropdown.enable();
diff --git a/spec/frontend/labels/delete_label_modal_spec.js b/spec/frontend/labels/delete_label_modal_spec.js
index 67220821fe0..98049538948 100644
--- a/spec/frontend/labels/delete_label_modal_spec.js
+++ b/spec/frontend/labels/delete_label_modal_spec.js
@@ -25,11 +25,11 @@ describe('DeleteLabelModal', () => {
buttons.forEach((x) => {
const button = document.createElement('button');
button.setAttribute('class', 'js-delete-label-modal-button');
- button.dataset.labelName = x.labelName;
- button.dataset.destroyPath = x.destroyPath;
+ button.setAttribute('data-label-name', x.labelName);
+ button.setAttribute('data-destroy-path', x.destroyPath);
if (x.subjectName) {
- button.dataset.subjectName = x.subjectName;
+ button.setAttribute('data-subject-name', x.subjectName);
}
button.innerHTML = 'Action';
diff --git a/spec/frontend/lazy_loader_spec.js b/spec/frontend/lazy_loader_spec.js
index e0b6c7119f9..3d8b0d9c307 100644
--- a/spec/frontend/lazy_loader_spec.js
+++ b/spec/frontend/lazy_loader_spec.js
@@ -27,7 +27,7 @@ describe('LazyLoader', () => {
const createLazyLoadImage = () => {
const newImg = document.createElement('img');
newImg.className = 'lazy';
- newImg.dataset.src = TEST_PATH;
+ newImg.setAttribute('data-src', TEST_PATH);
document.body.appendChild(newImg);
triggerChildMutation();
@@ -108,7 +108,7 @@ describe('LazyLoader', () => {
expect(LazyLoader.loadImage).toHaveBeenCalledWith(img);
expect(img.getAttribute('src')).toBe(TEST_PATH);
- expect(img.dataset.src).toBeUndefined();
+ expect(img.getAttribute('data-src')).toBe(null);
expect(img).toHaveClass('js-lazy-loaded');
});
diff --git a/spec/frontend/members/index_spec.js b/spec/frontend/members/index_spec.js
index 251a8b0b774..efabe54f238 100644
--- a/spec/frontend/members/index_spec.js
+++ b/spec/frontend/members/index_spec.js
@@ -24,7 +24,7 @@ describe('initMembersApp', () => {
beforeEach(() => {
el = document.createElement('div');
- el.dataset.membersData = dataAttribute;
+ el.setAttribute('data-members-data', dataAttribute);
window.gon = { current_user_id: 123 };
});
diff --git a/spec/frontend/members/utils_spec.js b/spec/frontend/members/utils_spec.js
index b0c9459ff4f..a157cfa1c1d 100644
--- a/spec/frontend/members/utils_spec.js
+++ b/spec/frontend/members/utils_spec.js
@@ -256,7 +256,7 @@ describe('Members Utils', () => {
beforeEach(() => {
el = document.createElement('div');
- el.dataset.membersData = dataAttribute;
+ el.setAttribute('data-members-data', dataAttribute);
});
afterEach(() => {
diff --git a/spec/frontend/notebook/cells/markdown_spec.js b/spec/frontend/notebook/cells/markdown_spec.js
index de415b5bfe0..7dc6f90d202 100644
--- a/spec/frontend/notebook/cells/markdown_spec.js
+++ b/spec/frontend/notebook/cells/markdown_spec.js
@@ -78,8 +78,8 @@ describe('Markdown component', () => {
});
await nextTick();
- expect(findLink().dataset.remote).toBeUndefined();
- expect(findLink().dataset.type).toBeUndefined();
+ expect(findLink().getAttribute('data-remote')).toBe(null);
+ expect(findLink().getAttribute('data-type')).toBe(null);
});
describe('When parsing images', () => {
diff --git a/spec/frontend/notes/stores/actions_spec.js b/spec/frontend/notes/stores/actions_spec.js
index b18acd591ed..75e7756cd6b 100644
--- a/spec/frontend/notes/stores/actions_spec.js
+++ b/spec/frontend/notes/stores/actions_spec.js
@@ -400,13 +400,13 @@ describe('Actions Notes Store', () => {
beforeEach(() => {
axiosMock.onDelete(endpoint).replyOnce(200, {});
- document.body.dataset.page = '';
+ document.body.setAttribute('data-page', '');
});
afterEach(() => {
axiosMock.restore();
- document.body.dataset.page = '';
+ document.body.setAttribute('data-page', '');
});
it('commits DELETE_NOTE and dispatches updateMergeRequestWidget', () => {
@@ -436,7 +436,7 @@ describe('Actions Notes Store', () => {
it('dispatches removeDiscussionsFromDiff on merge request page', () => {
const note = { path: endpoint, id: 1 };
- document.body.dataset.page = 'projects:merge_requests:show';
+ document.body.setAttribute('data-page', 'projects:merge_requests:show');
return testAction(
actions.removeNote,
@@ -469,13 +469,13 @@ describe('Actions Notes Store', () => {
beforeEach(() => {
axiosMock.onDelete(endpoint).replyOnce(200, {});
- document.body.dataset.page = '';
+ document.body.setAttribute('data-page', '');
});
afterEach(() => {
axiosMock.restore();
- document.body.dataset.page = '';
+ document.body.setAttribute('data-page', '');
});
it('dispatches removeNote', () => {
diff --git a/spec/frontend/performance_bar/index_spec.js b/spec/frontend/performance_bar/index_spec.js
index af256b1d335..91cb46002be 100644
--- a/spec/frontend/performance_bar/index_spec.js
+++ b/spec/frontend/performance_bar/index_spec.js
@@ -16,11 +16,11 @@ describe('performance bar wrapper', () => {
performance.getEntriesByType = jest.fn().mockReturnValue([]);
peekWrapper.setAttribute('id', 'js-peek');
- peekWrapper.dataset.env = 'development';
- peekWrapper.dataset.requestId = '123';
- peekWrapper.dataset.peekUrl = '/-/peek/results';
- peekWrapper.dataset.statsUrl = 'https://log.gprd.gitlab.net/app/dashboards#/view/';
- peekWrapper.dataset.profileUrl = '?lineprofiler=true';
+ peekWrapper.setAttribute('data-env', 'development');
+ peekWrapper.setAttribute('data-request-id', '123');
+ peekWrapper.setAttribute('data-peek-url', '/-/peek/results');
+ peekWrapper.setAttribute('data-stats-url', 'https://log.gprd.gitlab.net/app/dashboards#/view/');
+ peekWrapper.setAttribute('data-profile-url', '?lineprofiler=true');
mock = new MockAdapter(axios);
diff --git a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
index 615a3eaac47..04a93e8db25 100644
--- a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js
@@ -6,7 +6,7 @@ import { createMockDirective } from 'helpers/vue_mock_directive';
import PipelineEditorFileTreeContainer from '~/pipeline_editor/components/file_tree/container.vue';
import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue';
import { FILE_TREE_TIP_DISMISSED_KEY } from '~/pipeline_editor/constants';
-import { mockCiConfigPath, mockIncludes } from '../../mock_data';
+import { mockCiConfigPath, mockIncludes, mockIncludesHelpPagePath } from '../../mock_data';
describe('Pipeline editor file nav', () => {
let wrapper;
@@ -16,6 +16,7 @@ describe('Pipeline editor file nav', () => {
shallowMount(PipelineEditorFileTreeContainer, {
provide: {
ciConfigPath: mockCiConfigPath,
+ includesHelpPagePath: mockIncludesHelpPagePath,
},
propsData: {
includes,
@@ -64,6 +65,10 @@ describe('Pipeline editor file nav', () => {
expect(findTip().exists()).toBe(true);
});
+ it('renders learn more link', async () => {
+ expect(findTip().props('secondaryButtonLink')).toBe(mockIncludesHelpPagePath);
+ });
+
it('can dismiss the tip', async () => {
expect(findTip().exists()).toBe(true);
diff --git a/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js
index 28f3b68b3f7..98ce3f6ea40 100644
--- a/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js
+++ b/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js
@@ -1,16 +1,23 @@
import { nextTick } from 'vue';
-import { GlPopover } from '@gitlab/ui';
+import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue';
import { FILE_TREE_POPOVER_DISMISSED_KEY } from '~/pipeline_editor/constants';
+import { mockIncludesHelpPagePath } from '../../mock_data';
describe('FileTreePopover component', () => {
let wrapper;
const findPopover = () => wrapper.findComponent(GlPopover);
-
- const createComponent = (mountFn = shallowMount) => {
- wrapper = mountFn(FileTreePopover);
+ const findLink = () => findPopover().findComponent(GlLink);
+
+ const createComponent = ({ stubs } = {}) => {
+ wrapper = shallowMount(FileTreePopover, {
+ provide: {
+ includesHelpPagePath: mockIncludesHelpPagePath,
+ },
+ stubs,
+ });
};
afterEach(() => {
@@ -20,7 +27,7 @@ describe('FileTreePopover component', () => {
describe('default', () => {
beforeEach(async () => {
- createComponent();
+ createComponent({ stubs: { GlSprintf } });
});
it('renders dismissable popover', async () => {
@@ -31,6 +38,11 @@ describe('FileTreePopover component', () => {
expect(findPopover().exists()).toBe(false);
});
+
+ it('renders learn more link', () => {
+ expect(findLink().exists()).toBe(true);
+ expect(findLink().attributes('href')).toBe(mockIncludesHelpPagePath);
+ });
});
describe('when popover has already been dismissed before', () => {
diff --git a/spec/frontend/pipeline_editor/mock_data.js b/spec/frontend/pipeline_editor/mock_data.js
index 748519dfbae..560b2820fae 100644
--- a/spec/frontend/pipeline_editor/mock_data.js
+++ b/spec/frontend/pipeline_editor/mock_data.js
@@ -9,6 +9,7 @@ export const mockNewBranch = 'new-branch';
export const mockNewMergeRequestPath = '/-/merge_requests/new';
export const mockCommitSha = 'aabbccdd';
export const mockCommitNextSha = 'eeffgghh';
+export const mockIncludesHelpPagePath = '/-/includes/help';
export const mockLintHelpPagePath = '/-/lint-help';
export const mockLintUnavailableHelpPagePath = '/-/pipeline-editor/troubleshoot';
export const mockYmlHelpPagePath = '/-/yml-help';
diff --git a/spec/frontend/search_autocomplete_spec.js b/spec/frontend/search_autocomplete_spec.js
index 48e0aab6561..190f2803324 100644
--- a/spec/frontend/search_autocomplete_spec.js
+++ b/spec/frontend/search_autocomplete_spec.js
@@ -52,7 +52,7 @@ describe('Search autocomplete dropdown', () => {
};
const disableProjectIssues = () => {
- document.querySelector('.js-search-project-options').dataset.issuesDisabled = true;
+ document.querySelector('.js-search-project-options').setAttribute('data-issues-disabled', true);
};
// Mock `gl` object in window for dashboard specific page. App code will need it.
diff --git a/spec/frontend/user_popovers_spec.js b/spec/frontend/user_popovers_spec.js
index 3aa49eb8027..4edd526100a 100644
--- a/spec/frontend/user_popovers_spec.js
+++ b/spec/frontend/user_popovers_spec.js
@@ -22,7 +22,7 @@ describe('User Popovers', () => {
const link = document.createElement('a');
link.classList.add('js-user-link');
- link.dataset.user = '1';
+ link.setAttribute('data-user', '1');
return link;
};
diff --git a/spec/frontend/users_select/test_helper.js b/spec/frontend/users_select/test_helper.js
index 9231e38ea90..59edde48eab 100644
--- a/spec/frontend/users_select/test_helper.js
+++ b/spec/frontend/users_select/test_helper.js
@@ -95,10 +95,10 @@ export const setAssignees = (...users) => {
const input = document.createElement('input');
input.name = 'merge_request[assignee_ids][]';
input.value = user.id.toString();
- input.dataset.avatarUrl = user.avatar_url;
- input.dataset.name = user.name;
- input.dataset.username = user.username;
- input.dataset.canMerge = user.can_merge;
+ input.setAttribute('data-avatar-url', user.avatar_url);
+ input.setAttribute('data-name', user.name);
+ input.setAttribute('data-username', user.username);
+ input.setAttribute('data-can-merge', user.can_merge);
return input;
}),
);
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
index 29ee7e0010f..8efc4d84624 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -193,7 +193,9 @@ describe('MRWidgetMerged', () => {
it('shows button to copy commit SHA to clipboard', () => {
expect(selectors.copyMergeShaButton).not.toBe(null);
- expect(selectors.copyMergeShaButton.dataset.clipboardText).toBe(vm.mr.mergeCommitSha);
+ expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe(
+ vm.mr.mergeCommitSha,
+ );
});
it('hides button to copy commit SHA if SHA does not exist', async () => {
diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
index 1fe32605f09..9719e81fe12 100644
--- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
@@ -423,7 +423,7 @@ describe('MrWidgetOptions', () => {
beforeEach(() => {
const favicon = document.createElement('link');
favicon.setAttribute('id', 'favicon');
- favicon.dataset.originalHref = faviconDataUrl;
+ favicon.setAttribute('data-original-href', faviconDataUrl);
document.body.appendChild(favicon);
faviconElement = document.getElementById('favicon');
diff --git a/spec/frontend_integration/ide/helpers/ide_helper.js b/spec/frontend_integration/ide/helpers/ide_helper.js
index 4245e1f04c8..00ce39a5598 100644
--- a/spec/frontend_integration/ide/helpers/ide_helper.js
+++ b/spec/frontend_integration/ide/helpers/ide_helper.js
@@ -40,14 +40,14 @@ export const findMonacoDiffEditor = () =>
export const findAndSetEditorValue = async (value) => {
const editor = await findMonacoEditor();
- const { uri } = editor.dataset;
+ const uri = editor.getAttribute('data-uri');
monacoEditor.getModel(uri).setValue(value);
};
export const getEditorValue = async () => {
const editor = await findMonacoEditor();
- const { uri } = editor.dataset;
+ const uri = editor.getAttribute('data-uri');
return monacoEditor.getModel(uri).getValue();
};
diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb
index 12456deb538..429d4c7941a 100644
--- a/spec/helpers/ci/pipeline_editor_helper_spec.rb
+++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb
@@ -45,6 +45,7 @@ RSpec.describe Ci::PipelineEditorHelper do
"default-branch" => project.default_branch_or_main,
"empty-state-illustration-path" => 'foo',
"initial-branch-name" => nil,
+ "includes-help-page-path" => help_page_path('ci/yaml/includes'),
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'),
"lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'),
"needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'),
@@ -72,6 +73,7 @@ RSpec.describe Ci::PipelineEditorHelper do
"default-branch" => project.default_branch_or_main,
"empty-state-illustration-path" => 'foo',
"initial-branch-name" => nil,
+ "includes-help-page-path" => help_page_path('ci/yaml/includes'),
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'),
"lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'),
"needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'),
diff --git a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
index 39e782dc093..441a34b0c74 100644
--- a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do
let(:group_data) do
{
- 'name' => 'source_name',
+ 'name' => 'Source Group Name',
'full_path' => 'source/full/path',
'visibility' => 'private',
'project_creation_level' => 'developer',
diff --git a/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb
index e4a41428dd2..6949ac59948 100644
--- a/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, path: 'group') }
- let_it_be(:parent) { create(:group, name: 'imported-group', path: 'imported-group') }
+ let_it_be(:parent) { create(:group, name: 'Imported Group', path: 'imported-group') }
let_it_be(:parent_entity) { create(:bulk_import_entity, destination_namespace: parent.full_path, group: parent) }
let_it_be(:tracker) { create(:bulk_import_tracker, entity: parent_entity) }
let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
@@ -14,8 +14,8 @@ RSpec.describe BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline do
let(:extracted_data) do
BulkImports::Pipeline::ExtractedData.new(data: {
- 'name' => 'subgroup',
- 'full_path' => 'parent/subgroup'
+ 'path' => 'sub-group',
+ 'full_path' => 'parent/sub-group'
})
end
@@ -33,9 +33,9 @@ RSpec.describe BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline do
subgroup_entity = BulkImports::Entity.last
- expect(subgroup_entity.source_full_path).to eq 'parent/subgroup'
+ expect(subgroup_entity.source_full_path).to eq 'parent/sub-group'
expect(subgroup_entity.destination_namespace).to eq 'imported-group'
- expect(subgroup_entity.destination_name).to eq 'subgroup'
+ expect(subgroup_entity.destination_name).to eq 'sub-group'
expect(subgroup_entity.parent_id).to eq parent_entity.id
end
end
@@ -51,9 +51,7 @@ RSpec.describe BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline do
destination_namespace: parent_entity.group.full_path,
parent_id: parent_entity.id
}
-
expect { subject.load(context, data) }.to change(BulkImports::Entity, :count).by(1)
-
subgroup_entity = BulkImports::Entity.last
expect(subgroup_entity.source_full_path).to eq 'parent/subgroup'
diff --git a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
index 75d8c15088a..c42ca9bef3b 100644
--- a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
+++ b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do
describe '#transform' do
let_it_be(:user) { create(:user) }
let_it_be(:parent) { create(:group) }
- let_it_be(:group) { create(:group, name: 'My Source Group', parent: parent) }
let_it_be(:bulk_import) { create(:bulk_import, user: user) }
let_it_be(:entity) do
@@ -14,7 +13,7 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do
:bulk_import_entity,
bulk_import: bulk_import,
source_full_path: 'source/full/path',
- destination_name: group.name,
+ destination_name: 'destination-name-path',
destination_namespace: parent.full_path
)
end
@@ -24,7 +23,8 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do
let(:data) do
{
- 'name' => 'source_name',
+ 'name' => 'Source Group Name',
+ 'path' => 'source-group-path',
'full_path' => 'source/full/path',
'visibility' => 'private',
'project_creation_level' => 'developer',
@@ -34,23 +34,27 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do
subject { described_class.new }
- it 'transforms name to destination name' do
- transformed_data = subject.transform(context, data)
+ it 'returns original data with some keys transformed' do
+ transformed_data = subject.transform(context, { 'name' => 'Name', 'description' => 'Description' })
- expect(transformed_data['name']).not_to eq('source_name')
- expect(transformed_data['name']).to eq(group.name)
+ expect(transformed_data).to eq({
+ 'name' => 'Name',
+ 'description' => 'Description',
+ 'parent_id' => parent.id,
+ 'path' => 'destination-name-path'
+ })
end
- it 'removes full path' do
+ it 'transforms path from destination_name' do
transformed_data = subject.transform(context, data)
- expect(transformed_data).not_to have_key('full_path')
+ expect(transformed_data['path']).to eq(entity.destination_name)
end
- it 'transforms path to parameterized name' do
+ it 'removes full path' do
transformed_data = subject.transform(context, data)
- expect(transformed_data['path']).to eq(group.name.parameterize)
+ expect(transformed_data).not_to have_key('full_path')
end
it 'transforms visibility level' do
diff --git a/spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb
index 2f97a5721e7..6450d90ec0f 100644
--- a/spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb
+++ b/spec/lib/bulk_imports/groups/transformers/subgroup_to_entity_transformer_spec.rb
@@ -9,14 +9,14 @@ RSpec.describe BulkImports::Groups::Transformers::SubgroupToEntityTransformer do
parent_entity = instance_double(BulkImports::Entity, group: parent, id: 1)
context = instance_double(BulkImports::Pipeline::Context, entity: parent_entity)
subgroup_data = {
- "name" => "subgroup",
- "full_path" => "parent/subgroup"
+ "path" => "sub-group",
+ "full_path" => "parent/sub-group"
}
expect(subject.transform(context, subgroup_data)).to eq(
source_type: :group_entity,
- source_full_path: "parent/subgroup",
- destination_name: "subgroup",
+ source_full_path: "parent/sub-group",
+ destination_name: "sub-group",
destination_namespace: parent.full_path,
parent_id: 1
)
diff --git a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator/manual_otp_spec.rb
index dc20df98185..f08c787382e 100644
--- a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb
+++ b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator/manual_otp_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator do
+RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp do
let_it_be(:user) { create(:user) }
let(:otp_code) { 42 }
diff --git a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator/push_otp_spec.rb b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator/push_otp_spec.rb
new file mode 100644
index 00000000000..231bd3f48f1
--- /dev/null
+++ b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator/push_otp_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator::PushOtp do
+ let_it_be(:user) { create(:user) }
+
+ let(:host) { 'forti_authenticator.example.com' }
+ let(:port) { '444' }
+ let(:api_username) { 'janedoe' }
+ let(:api_token) { 's3cr3t' }
+
+ let(:forti_authenticator_auth_url) { "https://#{host}:#{port}/api/v1/pushauth/" }
+ let(:response_status) { 200 }
+
+ subject(:validate) { described_class.new(user).validate }
+
+ before do
+ stub_feature_flags(forti_authenticator: user)
+
+ stub_forti_authenticator_config(
+ enabled: true,
+ host: host,
+ port: port,
+ username: api_username,
+ access_token: api_token
+ )
+
+ request_body = { username: user.username }
+
+ stub_request(:post, forti_authenticator_auth_url)
+ .with(body: JSON(request_body),
+ headers: { 'Content-Type': 'application/json' },
+ basic_auth: [api_username, api_token])
+ .to_return(status: response_status, body: '')
+ end
+
+ context 'successful validation' do
+ it 'returns success' do
+ expect(validate[:status]).to eq(:success)
+ end
+ end
+
+ context 'unsuccessful validation' do
+ let(:response_status) { 401 }
+
+ it 'returns error' do
+ expect(validate[:status]).to eq(:error)
+ end
+ end
+
+ context 'unexpected error' do
+ it 'returns error' do
+ error_message = 'boom!'
+ stub_request(:post, forti_authenticator_auth_url).to_raise(StandardError.new(error_message))
+
+ expect(validate[:status]).to eq(:error)
+ expect(validate[:message]).to eq(error_message)
+ end
+ end
+
+ def stub_forti_authenticator_config(forti_authenticator_settings)
+ allow(::Gitlab.config.forti_authenticator).to(receive_messages(forti_authenticator_settings))
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb b/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb
new file mode 100644
index 00000000000..3f250d13e84
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/expire_o_auth_tokens_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::ExpireOAuthTokens, :migration, schema: 20220428133724 do
+ let(:migration) { described_class.new }
+ let(:oauth_access_tokens_table) { table(:oauth_access_tokens) }
+
+ let(:table_name) { 'oauth_access_tokens' }
+
+ subject(:perform_migration) do
+ described_class.new(start_id: 1,
+ end_id: 30,
+ batch_table: :oauth_access_tokens,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 0,
+ connection: ActiveRecord::Base.connection)
+ .perform(1000)
+ end
+
+ before do
+ oauth_access_tokens_table.create!(id: 1, token: 's3cr3t-1', expires_in: nil)
+ oauth_access_tokens_table.create!(id: 2, token: 's3cr3t-2', expires_in: 42)
+ oauth_access_tokens_table.create!(id: 3, token: 's3cr3t-3', expires_in: nil)
+ end
+
+ it 'adds expiry to oauth tokens', :aggregate_failures do
+ expect(ActiveRecord::QueryRecorder.new { perform_migration }.count).to eq(3)
+
+ expect(oauth_access_tokens_table.find(1).expires_in).to eq(7_200)
+ expect(oauth_access_tokens_table.find(2).expires_in).to eq(42)
+ expect(oauth_access_tokens_table.find(3).expires_in).to eq(7_200)
+ end
+end
diff --git a/spec/migrations/20220428133724_schedule_expire_o_auth_tokens_spec.rb b/spec/migrations/20220428133724_schedule_expire_o_auth_tokens_spec.rb
new file mode 100644
index 00000000000..05d1053a46c
--- /dev/null
+++ b/spec/migrations/20220428133724_schedule_expire_o_auth_tokens_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleExpireOAuthTokens do
+ let_it_be(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ it 'schedules background jobs for each batch of oauth tokens' do
+ migrate!
+
+ expect(migration).to(
+ have_scheduled_batched_migration(
+ table_name: :oauth_access_tokens,
+ column_name: :id,
+ interval: described_class::INTERVAL
+ )
+ )
+ end
+ end
+
+ describe '#down' do
+ it 'deletes all batched migration records' do
+ migrate!
+ schema_migrate_down!
+
+ expect(migration).not_to have_scheduled_batched_migration
+ end
+ end
+end
diff --git a/spec/migrations/20220505174658_update_index_on_alerts_to_exclude_null_fingerprints_spec.rb b/spec/migrations/20220505174658_update_index_on_alerts_to_exclude_null_fingerprints_spec.rb
new file mode 100644
index 00000000000..0c4d0e86789
--- /dev/null
+++ b/spec/migrations/20220505174658_update_index_on_alerts_to_exclude_null_fingerprints_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe UpdateIndexOnAlertsToExcludeNullFingerprints do
+ let(:alerts) { 'alert_management_alerts'}
+ let(:old_index) { described_class::OLD_INDEX_NAME }
+ let(:new_index) { described_class::NEW_INDEX_NAME }
+
+ it 'correctly migrates up and down' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(subject.index_exists_by_name?(alerts, old_index)).to be_truthy
+ expect(subject.index_exists_by_name?(alerts, new_index)).to be_falsey
+ }
+
+ migration.after -> {
+ expect(subject.index_exists_by_name?(alerts, old_index)).to be_falsey
+ expect(subject.index_exists_by_name?(alerts, new_index)).to be_truthy
+ }
+ end
+ end
+end
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb
index e709bee695c..685ed81ec84 100644
--- a/spec/models/alert_management/alert_spec.rb
+++ b/spec/models/alert_management/alert_spec.rb
@@ -233,13 +233,13 @@ RSpec.describe AlertManagement::Alert do
end
end
- describe '.find_ongoing_alert' do
+ describe '.find_unresolved_alert' do
let_it_be(:fingerprint) { SecureRandom.hex }
let_it_be(:resolved_alert_with_fingerprint) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint) }
let_it_be(:alert_with_fingerprint_in_other_project) { create(:alert_management_alert, project: project2, fingerprint: fingerprint) }
let_it_be(:alert_with_fingerprint) { create(:alert_management_alert, project: project, fingerprint: fingerprint) }
- subject { described_class.find_ongoing_alert(project, fingerprint) }
+ subject { described_class.find_unresolved_alert(project, fingerprint) }
it { is_expected.to eq(alert_with_fingerprint) }
end
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index c33e2bce65e..acfe476a864 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -1466,6 +1466,89 @@ RSpec.describe API::Internal::Base do
subject
expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq 'Feature is not available'
+ end
+ end
+
+ describe 'POST /internal/two_factor_manual_otp_check' do
+ let(:key_id) { key.id }
+ let(:otp) { '123456'}
+
+ subject do
+ post api('/internal/two_factor_manual_otp_check'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id,
+ otp_attempt: otp
+ }
+ end
+
+ it 'is not available' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq 'Feature is not available'
+ end
+ end
+
+ describe 'POST /internal/two_factor_push_otp_check' do
+ let(:key_id) { key.id }
+ let(:otp) { '123456'}
+
+ subject do
+ post api('/internal/two_factor_push_otp_check'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id,
+ otp_attempt: otp
+ }
+ end
+
+ it 'is not available' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq 'Feature is not available'
+ end
+ end
+
+ describe 'POST /internal/two_factor_manual_otp_check' do
+ let(:key_id) { key.id }
+ let(:otp) { '123456'}
+
+ subject do
+ post api('/internal/two_factor_manual_otp_check'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id,
+ otp_attempt: otp
+ }
+ end
+
+ it 'is not available' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ end
+ end
+
+ describe 'POST /internal/two_factor_push_otp_check' do
+ let(:key_id) { key.id }
+ let(:otp) { '123456'}
+
+ subject do
+ post api('/internal/two_factor_push_otp_check'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id,
+ otp_attempt: otp
+ }
+ end
+
+ it 'is not available' do
+ subject
+
+ expect(json_response['success']).to be_falsey
end
end
diff --git a/spec/services/alert_management/alerts/update_service_spec.rb b/spec/services/alert_management/alerts/update_service_spec.rb
index 882543fd701..f02607b8174 100644
--- a/spec/services/alert_management/alerts/update_service_spec.rb
+++ b/spec/services/alert_management/alerts/update_service_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
it_behaves_like 'title update'
end
- context 'when alert is resolved and another existing open alert' do
+ context 'when alert is resolved and another existing unresolved alert' do
let!(:alert) { create(:alert_management_alert, :resolved, project: project) }
let!(:existing_alert) { create(:alert_management_alert, :triggered, project: project) }
@@ -193,27 +193,38 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
end
end
- context 'with an opening status and existing open alert' do
- let_it_be(:alert) { create(:alert_management_alert, :resolved, :with_fingerprint, project: project) }
- let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) }
- let_it_be(:url) { Gitlab::Routing.url_helpers.details_project_alert_management_path(project, existing_alert) }
- let_it_be(:link) { ActionController::Base.helpers.link_to(_('alert'), url) }
+ context 'with existing unresolved alert' do
+ context 'with fingerprints' do
+ let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) }
- let(:message) do
- "An #{link} with the same fingerprint is already open. " \
- 'To change the status of this alert, resolve the linked alert.'
- end
+ it 'does not query for existing alerts' do
+ expect(::AlertManagement::Alert).not_to receive(:find_unresolved_alert)
- it_behaves_like 'does not add a todo'
- it_behaves_like 'does not add a system note'
+ response
+ end
- it 'has an informative message' do
- expect(response).to be_error
- expect(response.message).to eq(message)
+ context 'when status was resolved' do
+ let_it_be(:alert) { create(:alert_management_alert, :resolved, :with_fingerprint, project: project) }
+ let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) }
+
+ let(:url) { Gitlab::Routing.url_helpers.details_project_alert_management_path(project, existing_alert) }
+ let(:link) { ActionController::Base.helpers.link_to(_('alert'), url) }
+ let(:message) do
+ "An #{link} with the same fingerprint is already open. " \
+ 'To change the status of this alert, resolve the linked alert.'
+ end
+
+ it_behaves_like 'does not add a todo'
+ it_behaves_like 'does not add a system note'
+
+ it 'has an informative message' do
+ expect(response).to be_error
+ expect(response.message).to eq(message)
+ end
+ end
end
- context 'fingerprints are blank' do
- let_it_be(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: nil) }
+ context 'without fingerprints' do
let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) }
it 'successfully changes the status' do
diff --git a/spec/services/users/validate_otp_service_spec.rb b/spec/services/users/validate_manual_otp_service_spec.rb
index 46b80b2149f..d71735814f2 100644
--- a/spec/services/users/validate_otp_service_spec.rb
+++ b/spec/services/users/validate_manual_otp_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Users::ValidateOtpService do
+RSpec.describe Users::ValidateManualOtpService do
let_it_be(:user) { create(:user) }
let(:otp_code) { 42 }
@@ -25,8 +25,8 @@ RSpec.describe Users::ValidateOtpService do
allow(::Gitlab.config.forti_authenticator).to receive(:enabled).and_return(true)
end
- it 'calls FortiAuthenticator strategy' do
- expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator) do |strategy|
+ it 'calls ManualOtp strategy' do
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp) do |strategy|
expect(strategy).to receive(:validate).with(otp_code).once
end
@@ -48,4 +48,25 @@ RSpec.describe Users::ValidateOtpService do
validate
end
end
+
+ context 'unexpected error' do
+ before do
+ stub_feature_flags(forti_authenticator: user)
+ allow(::Gitlab.config.forti_authenticator).to receive(:enabled).and_return(true)
+ end
+
+ it 'returns error' do
+ error_message = "boom!"
+
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::ManualOtp) do |strategy|
+ expect(strategy).to receive(:validate).with(otp_code).once.and_raise(StandardError, error_message)
+ end
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+
+ result = validate
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq(error_message)
+ end
+ end
end
diff --git a/spec/services/users/validate_push_otp_service_spec.rb b/spec/services/users/validate_push_otp_service_spec.rb
new file mode 100644
index 00000000000..960b6bcd3bb
--- /dev/null
+++ b/spec/services/users/validate_push_otp_service_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::ValidatePushOtpService do
+ let_it_be(:user) { create(:user) }
+
+ subject(:validate) { described_class.new(user).execute }
+
+ context 'FortiAuthenticator' do
+ before do
+ stub_feature_flags(forti_authenticator: user)
+ allow(::Gitlab.config.forti_authenticator).to receive(:enabled).and_return(true)
+ end
+
+ it 'calls PushOtp strategy' do
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::PushOtp) do |strategy|
+ expect(strategy).to receive(:validate).once
+ end
+
+ validate
+ end
+ end
+
+ context 'unexpected error' do
+ before do
+ stub_feature_flags(forti_authenticator: user)
+ allow(::Gitlab.config.forti_authenticator).to receive(:enabled).and_return(true)
+ end
+
+ it 'returns error' do
+ error_message = "boom!"
+
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator::PushOtp) do |strategy|
+ expect(strategy).to receive(:validate).once.and_raise(StandardError, error_message)
+ end
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+
+ result = validate
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq(error_message)
+ end
+ end
+end