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-07-21 21:10:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-21 21:10:08 +0300
commit5d41ea8c8e83ff6054ba4303ec8dc9bc33556602 (patch)
treef69079c9fac34f1e5e785d1f18d2f9ad339e4cbc /spec
parenta09c6d7e91de9abab7e2ea8dffce1cbb89bf95d8 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/commands/sidekiq_cluster/cli_spec.rb4
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb14
-rw-r--r--spec/frontend/attention_requests/components/navigation_popover_spec.js88
-rw-r--r--spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js6
-rw-r--r--spec/frontend/runner/components/registration/registration_token_spec.js27
-rw-r--r--spec/frontend/sidebar/components/attention_requested_toggle_spec.js121
-rw-r--r--spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js15
-rw-r--r--spec/frontend/sidebar/sidebar_mediator_spec.js92
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js9
-rw-r--r--spec/frontend/work_items_hierarchy/components/app_spec.js8
-rw-r--r--spec/frontend/work_items_hierarchy/components/hierarchy_spec.js7
-rw-r--r--spec/graphql/types/project_type_spec.rb4
-rw-r--r--spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb54
-rw-r--r--spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb15
-rw-r--r--spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb91
-rw-r--r--spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb7
-rw-r--r--spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb7
-rw-r--r--spec/lib/gitlab/github_import/importer/events/closed_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/events/renamed_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/events/reopened_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb22
-rw-r--r--spec/lib/gitlab/github_import/representation/issue_event_spec.rb33
-rw-r--r--spec/lib/gitlab/github_import/user_finder_spec.rb66
-rw-r--r--spec/lib/gitlab/import_export/project/relation_saver_spec.rb125
-rw-r--r--spec/models/environment_spec.rb10
-rw-r--r--spec/models/projects/import_export/relation_export_spec.rb32
-rw-r--r--spec/services/projects/import_export/relation_export_service_spec.rb121
-rw-r--r--spec/services/security/ci_configuration/sast_parser_service_spec.rb1
-rw-r--r--spec/services/work_items/create_and_link_service_spec.rb2
-rw-r--r--spec/services/work_items/create_from_task_service_spec.rb2
-rw-r--r--spec/support/helpers/ci/template_helpers.rb4
-rw-r--r--spec/support/shared_examples/services/work_items/create_task_shared_examples.rb16
-rw-r--r--spec/workers/projects/import_export/relation_export_worker_spec.rb36
34 files changed, 601 insertions, 478 deletions
diff --git a/spec/commands/sidekiq_cluster/cli_spec.rb b/spec/commands/sidekiq_cluster/cli_spec.rb
index 55e8ab7885e..4d1a07a6a75 100644
--- a/spec/commands/sidekiq_cluster/cli_spec.rb
+++ b/spec/commands/sidekiq_cluster/cli_spec.rb
@@ -245,9 +245,9 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, stub_settings_source: true do # rubo
it 'expands multiple queue groups correctly' do
expected_workers =
if Gitlab.ee?
- [%w[chat_notification], %w[project_export project_template_export]]
+ [%w[chat_notification], %w[project_export projects_import_export_relation_export project_template_export]]
else
- [%w[chat_notification], %w[project_export]]
+ [%w[chat_notification], %w[project_export projects_import_export_relation_export]]
end
expect(Gitlab::SidekiqCluster)
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index fa866beb773..cf9760bcd7f 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -9,8 +9,6 @@ RSpec.describe 'Merge requests > User mass updates', :js do
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
before do
- stub_feature_flags(mr_attention_requests: false)
-
project.add_maintainer(user)
project.add_maintainer(user2)
sign_in(user)
@@ -63,18 +61,6 @@ RSpec.describe 'Merge requests > User mass updates', :js do
expect(find('.merge-request')).to have_link "Assigned to #{user.name}"
end
-
- describe 'with attention requests feature flag on' do
- before do
- stub_feature_flags(mr_attention_requests: true)
- end
-
- it 'updates merge request with assignee' do
- change_assignee(user2.name)
-
- expect(find('.issuable-meta a.author-link')[:title]).to eq "Attention requested from assignee #{user2.name}"
- end
- end
end
describe 'remove assignee' do
diff --git a/spec/frontend/attention_requests/components/navigation_popover_spec.js b/spec/frontend/attention_requests/components/navigation_popover_spec.js
deleted file mode 100644
index e4d53d5dbdb..00000000000
--- a/spec/frontend/attention_requests/components/navigation_popover_spec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlPopover, GlButton, GlSprintf, GlIcon } from '@gitlab/ui';
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import NavigationPopover from '~/attention_requests/components/navigation_popover.vue';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
-
-let wrapper;
-let dismiss;
-
-function createComponent(provideData = {}, shouldShowCallout = true) {
- wrapper = shallowMount(NavigationPopover, {
- provide: {
- message: ['Test'],
- observerElSelector: '.js-test',
- observerElToggledClass: 'show',
- featureName: 'attention_requests',
- popoverTarget: '.js-test-popover',
- ...provideData,
- },
- stubs: {
- UserCalloutDismisser: makeMockUserCalloutDismisser({
- dismiss,
- shouldShowCallout,
- }),
- GlSprintf,
- },
- });
-}
-
-describe('Attention requests navigation popover', () => {
- beforeEach(() => {
- setHTMLFixture('<div><div class="js-test-popover"></div><div class="js-test"></div></div>');
- dismiss = jest.fn();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- resetHTMLFixture();
- });
-
- it('hides popover if callout is disabled', () => {
- createComponent({}, false);
-
- expect(wrapper.findComponent(GlPopover).exists()).toBe(false);
- });
-
- it('shows popover if callout is enabled', () => {
- createComponent();
-
- expect(wrapper.findComponent(GlPopover).exists()).toBe(true);
- });
-
- it.each`
- isDesktop | device | expectedPlacement
- ${true} | ${'desktop'} | ${'left'}
- ${false} | ${'mobile'} | ${'bottom'}
- `(
- 'sets popover position to $expectedPlacement on $device',
- ({ isDesktop, expectedPlacement }) => {
- jest.spyOn(bp, 'isDesktop').mockReturnValue(isDesktop);
-
- createComponent();
-
- expect(wrapper.findComponent(GlPopover).props('placement')).toBe(expectedPlacement);
- },
- );
-
- it('calls dismiss when clicking action button', () => {
- createComponent();
-
- wrapper
- .findComponent(GlButton)
- .vm.$emit('click', { preventDefault() {}, stopPropagation() {} });
-
- expect(dismiss).toHaveBeenCalled();
- });
-
- it('shows icon in text', () => {
- createComponent({ showAttentionIcon: true, message: ['%{strongStart}Test%{strongEnd}'] });
-
- const icon = wrapper.findComponent(GlIcon);
-
- expect(icon.exists()).toBe(true);
- expect(icon.props('name')).toBe('attention');
- });
-});
diff --git a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
index 87a7f07f7d4..d990d5ad22b 100644
--- a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
+++ b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
@@ -1,5 +1,5 @@
import { GlAlert, GlBadge, GlLoadingIcon, GlTabs } from '@gitlab/ui';
-import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
+import { mount, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vue, { nextTick } from 'vue';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -30,8 +30,7 @@ import {
mockLintResponseWithoutMerged,
} from '../mock_data';
-const localVue = createLocalVue();
-localVue.use(VueApollo);
+Vue.use(VueApollo);
Vue.config.ignoredElements = ['gl-emoji'];
@@ -88,7 +87,6 @@ describe('Pipeline editor tabs component', () => {
provide,
mountFn,
options: {
- localVue,
apolloProvider: mockApollo,
},
});
diff --git a/spec/frontend/runner/components/registration/registration_token_spec.js b/spec/frontend/runner/components/registration/registration_token_spec.js
index ed1a698d36f..19344a68f79 100644
--- a/spec/frontend/runner/components/registration/registration_token_spec.js
+++ b/spec/frontend/runner/components/registration/registration_token_spec.js
@@ -1,5 +1,5 @@
import { GlToast } from '@gitlab/ui';
-import { createLocalVue } from '@vue/test-utils';
+import Vue from 'vue';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import RegistrationToken from '~/runner/components/registration/registration_token.vue';
import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
@@ -11,28 +11,17 @@ describe('RegistrationToken', () => {
let wrapper;
let showToast;
- const findInputCopyToggleVisibility = () => wrapper.findComponent(InputCopyToggleVisibility);
-
- const vueWithGlToast = () => {
- const localVue = createLocalVue();
- localVue.use(GlToast);
- return localVue;
- };
+ Vue.use(GlToast);
- const createComponent = ({
- props = {},
- withGlToast = true,
- mountFn = shallowMountExtended,
- } = {}) => {
- const localVue = withGlToast ? vueWithGlToast() : undefined;
+ const findInputCopyToggleVisibility = () => wrapper.findComponent(InputCopyToggleVisibility);
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
wrapper = mountFn(RegistrationToken, {
propsData: {
value: mockToken,
inputId: 'token-value',
...props,
},
- localVue,
});
showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
@@ -69,13 +58,5 @@ describe('RegistrationToken', () => {
expect(showToast).toHaveBeenCalledTimes(1);
expect(showToast).toHaveBeenCalledWith('Registration token copied!');
});
-
- it('does not fail when toast is not defined', () => {
- createComponent({ withGlToast: false });
- findInputCopyToggleVisibility().vm.$emit('copy');
-
- // This block also tests for unhandled errors
- expect(showToast).toBeNull();
- });
});
});
diff --git a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js
deleted file mode 100644
index 58fa878a189..00000000000
--- a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import AttentionRequestedToggle from '~/sidebar/components/attention_requested_toggle.vue';
-
-let wrapper;
-
-function factory(propsData = {}) {
- wrapper = mount(AttentionRequestedToggle, { propsData });
-}
-
-const findToggle = () => wrapper.findComponent(GlButton);
-
-describe('Attention require toggle', () => {
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders button', () => {
- factory({
- type: 'reviewer',
- user: { attention_requested: false, can_update_merge_request: true },
- });
-
- expect(findToggle().exists()).toBe(true);
- });
-
- it.each`
- attentionRequested | icon
- ${true} | ${'attention-solid'}
- ${false} | ${'attention'}
- `(
- 'renders $icon icon when attention_requested is $attentionRequested',
- ({ attentionRequested, icon }) => {
- factory({
- type: 'reviewer',
- user: { attention_requested: attentionRequested, can_update_merge_request: true },
- });
-
- expect(findToggle().props('icon')).toBe(icon);
- },
- );
-
- it.each`
- attentionRequested | selected
- ${true} | ${true}
- ${false} | ${false}
- `(
- 'renders button with as selected when $selected when attention_requested is $attentionRequested',
- ({ attentionRequested, selected }) => {
- factory({
- type: 'reviewer',
- user: { attention_requested: attentionRequested, can_update_merge_request: true },
- });
-
- expect(findToggle().props('selected')).toBe(selected);
- },
- );
-
- it('emits toggle-attention-requested on click', async () => {
- factory({
- type: 'reviewer',
- user: { attention_requested: true, can_update_merge_request: true },
- });
-
- await findToggle().trigger('click');
-
- expect(wrapper.emitted('toggle-attention-requested')[0]).toEqual([
- {
- user: { attention_requested: true, can_update_merge_request: true },
- callback: expect.anything(),
- direction: 'remove',
- },
- ]);
- });
-
- it('does not emit toggle-attention-requested on click if can_update_merge_request is false', async () => {
- factory({
- type: 'reviewer',
- user: { attention_requested: true, can_update_merge_request: false },
- });
-
- await findToggle().trigger('click');
-
- expect(wrapper.emitted('toggle-attention-requested')).toBe(undefined);
- });
-
- it('sets loading on click', async () => {
- factory({
- type: 'reviewer',
- user: { attention_requested: true, can_update_merge_request: true },
- });
-
- await findToggle().trigger('click');
-
- expect(findToggle().props('loading')).toBe(true);
- });
-
- it.each`
- type | attentionRequested | tooltip | canUpdateMergeRequest
- ${'reviewer'} | ${true} | ${AttentionRequestedToggle.i18n.removeAttentionRequest} | ${true}
- ${'reviewer'} | ${false} | ${AttentionRequestedToggle.i18n.addAttentionRequest} | ${true}
- ${'assignee'} | ${false} | ${AttentionRequestedToggle.i18n.addAttentionRequest} | ${true}
- ${'reviewer'} | ${true} | ${AttentionRequestedToggle.i18n.attentionRequestedNoPermission} | ${false}
- ${'reviewer'} | ${false} | ${AttentionRequestedToggle.i18n.noAttentionRequestedNoPermission} | ${false}
- ${'assignee'} | ${true} | ${AttentionRequestedToggle.i18n.attentionRequestedNoPermission} | ${false}
- ${'assignee'} | ${false} | ${AttentionRequestedToggle.i18n.noAttentionRequestedNoPermission} | ${false}
- `(
- 'sets tooltip as $tooltip when attention_requested is $attentionRequested, type is $type and, can_update_merge_request is $canUpdateMergeRequest',
- ({ type, attentionRequested, tooltip, canUpdateMergeRequest }) => {
- factory({
- type,
- user: {
- attention_requested: attentionRequested,
- can_update_merge_request: canUpdateMergeRequest,
- },
- });
-
- expect(findToggle().attributes('aria-label')).toBe(tooltip);
- },
- );
-});
diff --git a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
index 8999f120a0f..8ac85d4da81 100644
--- a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
@@ -1,6 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
-import AttentionRequestedToggle from '~/sidebar/components/attention_requested_toggle.vue';
import ReviewerAvatarLink from '~/sidebar/components/reviewers/reviewer_avatar_link.vue';
import UncollapsedReviewerList from '~/sidebar/components/reviewers/uncollapsed_reviewer_list.vue';
import userDataMock from '../../user_data_mock';
@@ -119,18 +118,4 @@ describe('UncollapsedReviewerList component', () => {
expect(wrapper.find('[data-testid="re-request-success"]').exists()).toBe(true);
});
});
-
- it('hides re-request review button when attentionRequired feature flag is enabled', () => {
- createComponent({ users: [userDataMock()] }, { mrAttentionRequests: true });
-
- expect(wrapper.findAll('[data-testid="re-request-button"]').length).toBe(0);
- });
-
- it('emits toggle-attention-requested', () => {
- createComponent({ users: [userDataMock()] }, { mrAttentionRequests: true });
-
- wrapper.find(AttentionRequestedToggle).vm.$emit('toggle-attention-requested', 'data');
-
- expect(wrapper.emitted('toggle-attention-requested')[0]).toEqual(['data']);
- });
});
diff --git a/spec/frontend/sidebar/sidebar_mediator_spec.js b/spec/frontend/sidebar/sidebar_mediator_spec.js
index 82fb10ab1d2..e32694abcce 100644
--- a/spec/frontend/sidebar/sidebar_mediator_spec.js
+++ b/spec/frontend/sidebar/sidebar_mediator_spec.js
@@ -1,12 +1,9 @@
import MockAdapter from 'axios-mock-adapter';
-import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import * as urlUtility from '~/lib/utils/url_utility';
import SidebarService, { gqClient } from '~/sidebar/services/sidebar_service';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarStore from '~/sidebar/stores/sidebar_store';
-import toast from '~/vue_shared/plugins/global_toast';
-import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import Mock from './mock_data';
jest.mock('~/flash');
@@ -122,93 +119,4 @@ describe('Sidebar mediator', () => {
urlSpy.mockRestore();
});
});
-
- describe('toggleAttentionRequested', () => {
- let requestAttentionMock;
- let removeAttentionRequestMock;
-
- beforeEach(() => {
- requestAttentionMock = jest.spyOn(mediator.service, 'requestAttention').mockResolvedValue();
- removeAttentionRequestMock = jest
- .spyOn(mediator.service, 'removeAttentionRequest')
- .mockResolvedValue();
- });
-
- it.each`
- attentionIsCurrentlyRequested | serviceMethod
- ${true} | ${'remove'}
- ${false} | ${'add'}
- `(
- "calls the $serviceMethod service method when the user's attention request is set to $attentionIsCurrentlyRequested",
- async ({ serviceMethod }) => {
- const methods = {
- add: requestAttentionMock,
- remove: removeAttentionRequestMock,
- };
- mediator.store.reviewers = [{ id: 1, attention_requested: false, username: 'root' }];
-
- await mediator.toggleAttentionRequested('reviewer', {
- user: { id: 1, username: 'root' },
- callback: jest.fn(),
- direction: serviceMethod,
- });
-
- expect(methods[serviceMethod]).toHaveBeenCalledWith(1);
- expect(refreshUserMergeRequestCounts).toHaveBeenCalled();
- },
- );
-
- it.each`
- type | method
- ${'reviewer'} | ${'findReviewer'}
- `('finds $type', ({ type, method }) => {
- const methodSpy = jest.spyOn(mediator.store, method);
-
- mediator.toggleAttentionRequested(type, { user: { id: 1 }, callback: jest.fn() });
-
- expect(methodSpy).toHaveBeenCalledWith({ id: 1 });
- });
-
- it.each`
- attentionRequested | toastMessage
- ${true} | ${'Removed attention request from @root'}
- ${false} | ${'Requested attention from @root'}
- `(
- 'it creates toast $toastMessage when attention_requested is $attentionRequested',
- async ({ attentionRequested, toastMessage }) => {
- mediator.store.reviewers = [
- { id: 1, attention_requested: attentionRequested, username: 'root' },
- ];
-
- await mediator.toggleAttentionRequested('reviewer', {
- user: { id: 1, username: 'root' },
- callback: jest.fn(),
- });
-
- expect(toast).toHaveBeenCalledWith(toastMessage);
- },
- );
-
- describe('errors', () => {
- beforeEach(() => {
- jest
- .spyOn(mediator.service, 'removeAttentionRequest')
- .mockRejectedValueOnce(new Error('Something went wrong'));
- });
-
- it('shows an error message', async () => {
- await mediator.toggleAttentionRequested('reviewer', {
- user: { id: 1, username: 'root' },
- callback: jest.fn(),
- direction: 'remove',
- });
-
- expect(createFlash).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'Updating the attention request for root failed.',
- }),
- );
- });
- });
- });
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index 46d90ddc83c..188582d2e05 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -1,5 +1,5 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
import { GlSprintf } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import produce from 'immer';
@@ -71,8 +71,8 @@ const createTestService = () => ({
merge: jest.fn(),
poll: jest.fn().mockResolvedValue(),
});
-const localVue = createLocalVue();
-localVue.use(VueApollo);
+
+Vue.use(VueApollo);
let wrapper;
let readyToMergeResponseSpy;
@@ -93,7 +93,6 @@ const createComponent = (
restructuredMrWidget = false,
) => {
wrapper = shallowMount(ReadyToMerge, {
- localVue,
propsData: {
mr: createTestMr(customConfig),
service: createTestService(),
diff --git a/spec/frontend/work_items_hierarchy/components/app_spec.js b/spec/frontend/work_items_hierarchy/components/app_spec.js
index 092e9c90553..1426fbfab80 100644
--- a/spec/frontend/work_items_hierarchy/components/app_spec.js
+++ b/spec/frontend/work_items_hierarchy/components/app_spec.js
@@ -1,19 +1,17 @@
-import { nextTick } from 'vue';
-import { createLocalVue, mount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import { GlBanner } from '@gitlab/ui';
import App from '~/work_items_hierarchy/components/app.vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-const localVue = createLocalVue();
-localVue.use(VueApollo);
+Vue.use(VueApollo);
describe('WorkItemsHierarchy App', () => {
let wrapper;
const createComponent = (props = {}, data = {}) => {
wrapper = extendedWrapper(
mount(App, {
- localVue,
provide: {
illustrationPath: '/foo.svg',
licensePlan: 'free',
diff --git a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js b/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
index 74774e38d6b..67420e7fc2a 100644
--- a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
+++ b/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js
@@ -1,4 +1,5 @@
-import { createLocalVue, mount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
+import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlBadge } from '@gitlab/ui';
import Hierarchy from '~/work_items_hierarchy/components/hierarchy.vue';
@@ -6,8 +7,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import RESPONSE from '~/work_items_hierarchy/static_response';
import { workItemTypes } from '~/work_items_hierarchy/constants';
-const localVue = createLocalVue();
-localVue.use(VueApollo);
+Vue.use(VueApollo);
describe('WorkItemsHierarchy Hierarchy', () => {
let wrapper;
@@ -32,7 +32,6 @@ describe('WorkItemsHierarchy Hierarchy', () => {
const createComponent = (props = {}) => {
wrapper = extendedWrapper(
mount(Hierarchy, {
- localVue,
propsData: {
workItemTypes: props.workItemTypes,
...props,
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index ed93d31da0f..6b769230d92 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -195,8 +195,8 @@ RSpec.describe GitlabSchema.types['Project'] do
expect(secure_analyzers['type']).to eq('string')
expect(secure_analyzers['field']).to eq('SECURE_ANALYZERS_PREFIX')
expect(secure_analyzers['label']).to eq('Image prefix')
- expect(secure_analyzers['defaultValue']).to eq(secure_analyzers_prefix)
- expect(secure_analyzers['value']).to eq(secure_analyzers_prefix)
+ expect(secure_analyzers['defaultValue']).to eq('$TEMPLATE_REGISTRY_HOST/security-products')
+ expect(secure_analyzers['value']).to eq('$TEMPLATE_REGISTRY_HOST/security-products')
expect(secure_analyzers['size']).to eq('LARGE')
expect(secure_analyzers['options']).to be_nil
end
diff --git a/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb b/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb
deleted file mode 100644
index 7c78d8b0305..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillCiRunnerSemver, :migration, schema: 20220601151900 do
- let(:ci_runners) { table(:ci_runners, database: :ci) }
-
- subject do
- described_class.new(
- start_id: 10,
- end_id: 15,
- batch_table: :ci_runners,
- batch_column: :id,
- sub_batch_size: 10,
- pause_ms: 0,
- connection: Ci::ApplicationRecord.connection)
- end
-
- describe '#perform' do
- it 'populates semver column on all runners in range' do
- ci_runners.create!(id: 10, runner_type: 1, version: %q(HEAD-fd84d97))
- ci_runners.create!(id: 11, runner_type: 1, version: %q(v1.2.3))
- ci_runners.create!(id: 12, runner_type: 1, version: %q(2.1.0))
- ci_runners.create!(id: 13, runner_type: 1, version: %q(11.8.0~beta.935.g7f6d2abc))
- ci_runners.create!(id: 14, runner_type: 1, version: %q(13.2.2/1.1.0))
- ci_runners.create!(id: 15, runner_type: 1, version: %q('14.3.4'))
-
- subject.perform
-
- expect(ci_runners.all).to contain_exactly(
- an_object_having_attributes(id: 10, semver: nil),
- an_object_having_attributes(id: 11, semver: '1.2.3'),
- an_object_having_attributes(id: 12, semver: '2.1.0'),
- an_object_having_attributes(id: 13, semver: '11.8.0'),
- an_object_having_attributes(id: 14, semver: '13.2.2'),
- an_object_having_attributes(id: 15, semver: '14.3.4')
- )
- end
-
- it 'skips runners that already have semver value' do
- ci_runners.create!(id: 10, runner_type: 1, version: %q(1.2.4), semver: '1.2.3')
- ci_runners.create!(id: 11, runner_type: 1, version: %q(1.2.5))
- ci_runners.create!(id: 12, runner_type: 1, version: %q(HEAD), semver: '1.2.4')
-
- subject.perform
-
- expect(ci_runners.all).to contain_exactly(
- an_object_having_attributes(id: 10, semver: '1.2.3'),
- an_object_having_attributes(id: 11, semver: '1.2.5'),
- an_object_having_attributes(id: 12, semver: '1.2.4')
- )
- end
- end
-end
diff --git a/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb b/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb
new file mode 100644
index 00000000000..f113ffcd0a7
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::Events::BaseImporter do
+ let(:project) { instance_double('Project') }
+ let(:user_finder) { instance_double('Gitlab::GithubImport::UserFinder') }
+ let(:issue_event) { instance_double('Gitlab::GithubImport::Representation::IssueEvent') }
+ let(:importer_class) { Class.new(described_class) }
+ let(:importer_instance) { importer_class.new(project, user_finder) }
+
+ describe '#execute' do
+ it { expect { importer_instance.execute(issue_event) }.to raise_error(NotImplementedError) }
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb
new file mode 100644
index 00000000000..a1918dd0da8
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedAssignee do
+ subject(:importer) { described_class.new(project, user_finder) }
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:assignee) { create(:user) }
+ let_it_be(:assigner) { create(:user) }
+
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
+ let(:issue) { create(:issue, project: project) }
+
+ let(:issue_event) do
+ Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
+ 'id' => 6501124486,
+ 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'event' => event_type,
+ 'commit_id' => nil,
+ 'created_at' => '2022-04-26 18:30:53 UTC',
+ 'assigner' => { 'id' => assigner.id, 'login' => assigner.username },
+ 'assignee' => { 'id' => assignee.id, 'login' => assignee.username },
+ 'issue_db_id' => issue.id
+ )
+ end
+
+ let(:note_attrs) do
+ {
+ noteable_id: issue.id,
+ noteable_type: Issue.name,
+ project_id: project.id,
+ author_id: assigner.id,
+ system: true,
+ created_at: issue_event.created_at,
+ updated_at: issue_event.created_at
+ }.stringify_keys
+ end
+
+ let(:expected_system_note_metadata_attrs) do
+ {
+ action: "assignee",
+ created_at: issue_event.created_at,
+ updated_at: issue_event.created_at
+ }.stringify_keys
+ end
+
+ shared_examples 'new note' do
+ it 'creates expected note' do
+ expect { importer.execute(issue_event) }.to change { issue.notes.count }
+ .from(0).to(1)
+
+ expect(issue.notes.last)
+ .to have_attributes(expected_note_attrs)
+ end
+
+ it 'creates expected system note metadata' do
+ expect { importer.execute(issue_event) }.to change { SystemNoteMetadata.count }
+ .from(0).to(1)
+
+ expect(SystemNoteMetadata.last)
+ .to have_attributes(
+ expected_system_note_metadata_attrs.merge(
+ note_id: Note.last.id
+ )
+ )
+ end
+ end
+
+ describe '#execute' do
+ before do
+ allow(user_finder).to receive(:find).with(assignee.id, assignee.username).and_return(assignee.id)
+ allow(user_finder).to receive(:find).with(assigner.id, assigner.username).and_return(assigner.id)
+ end
+
+ context 'when importing an assigned event' do
+ let(:event_type) { 'assigned' }
+ let(:expected_note_attrs) { note_attrs.merge(note: "assigned to @#{assignee.username}") }
+
+ it_behaves_like 'new note'
+ end
+
+ context 'when importing an unassigned event' do
+ let(:event_type) { 'unassigned' }
+ let(:expected_note_attrs) { note_attrs.merge(note: "unassigned @#{assigner.username}") }
+
+ it_behaves_like 'new note'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
index b773598853d..98a8daf1653 100644
--- a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
@@ -3,18 +3,20 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue) { create(:issue, project: project) }
let!(:label) { create(:label, project: project) }
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
'id' => 6501124486,
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => event_type,
'commit_id' => nil,
'label_title' => label.title,
@@ -43,6 +45,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(label.id)
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
end
context 'when importing a labeled event' do
diff --git a/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb
index 5db708b9049..a5852c967df 100644
--- a/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/changed_milestone_spec.rb
@@ -3,18 +3,20 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedMilestone do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue) { create(:issue, project: project) }
let!(:milestone) { create(:milestone, project: project) }
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
'id' => 6501124486,
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => event_type,
'commit_id' => nil,
'milestone_title' => milestone.title,
@@ -45,6 +47,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedMilestone do
describe '#execute' do
before do
allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(milestone.id)
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
end
context 'when importing a milestoned event' do
diff --git a/spec/lib/gitlab/github_import/importer/events/closed_spec.rb b/spec/lib/gitlab/github_import/importer/events/closed_spec.rb
index 116917d3e06..749c52a215e 100644
--- a/spec/lib/gitlab/github_import/importer/events/closed_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/closed_spec.rb
@@ -3,11 +3,13 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue) { create(:issue, project: project) }
let(:commit_id) { nil }
@@ -16,7 +18,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do
'id' => 6501124486,
'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG',
'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486',
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => 'closed',
'created_at' => '2022-04-26 18:30:53 UTC',
'commit_id' => commit_id,
@@ -45,6 +47,10 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Closed do
}.stringify_keys
end
+ before do
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
+ end
+
it 'creates expected event and state event' do
importer.execute(issue_event)
diff --git a/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb b/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb
index 118c482a7d9..bf785d27f05 100644
--- a/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/cross_referenced_spec.rb
@@ -3,12 +3,14 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_gitlab_redis_cache do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:sawyer_stub) { Struct.new(:iid, :issuable_type, keyword_init: true) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue) { create(:issue, project: project) }
let(:referenced_in) { build_stubbed(:issue, project: project) }
@@ -19,7 +21,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
'id' => 6501124486,
'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG',
'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486',
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => 'cross-referenced',
'source' => {
'type' => 'issue',
@@ -53,6 +55,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
other_issue_resource = sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'Issue')
Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource)
.cache_database_id(referenced_in.iid)
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
end
it 'creates expected note' do
@@ -75,6 +78,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
sawyer_stub.new(iid: referenced_in.iid, issuable_type: 'MergeRequest')
Gitlab::GithubImport::IssuableFinder.new(project, other_issue_resource)
.cache_database_id(referenced_in.iid)
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
end
it 'creates expected note' do
@@ -87,7 +91,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::CrossReferenced, :clean_g
end
context 'when referenced in out of project issue/pull_request' do
- it 'creates expected note' do
+ it 'does not create expected note' do
importer.execute(issue_event)
expect(issue.notes.count).to eq 0
diff --git a/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb b/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb
index a8c3fbcb05d..8acf82af40c 100644
--- a/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/renamed_spec.rb
@@ -3,17 +3,19 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::Renamed do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:issue) { create(:issue, project: project) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
'id' => 6501124486,
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => 'renamed',
'commit_id' => nil,
'created_at' => '2022-04-26 18:30:53 UTC',
@@ -45,6 +47,10 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Renamed do
end
describe '#execute' do
+ before do
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
+ end
+
it 'creates expected note' do
expect { importer.execute(issue_event) }.to change { issue.notes.count }
.from(0).to(1)
diff --git a/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb b/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb
index 81653b0ecdc..39b8809dfa4 100644
--- a/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/reopened_spec.rb
@@ -3,11 +3,13 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_failures do
- subject(:importer) { described_class.new(project, user.id) }
+ subject(:importer) { described_class.new(project, user_finder) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:user_finder) { Gitlab::GithubImport::UserFinder.new(project, client) }
let(:issue) { create(:issue, project: project) }
let(:issue_event) do
@@ -15,7 +17,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_fail
'id' => 6501124486,
'node_id' => 'CE_lADOHK9fA85If7x0zwAAAAGDf0mG',
'url' => 'https://api.github.com/repos/elhowm/test-import/issues/events/6501124486',
- 'actor' => { 'id' => 4, 'login' => 'alice' },
+ 'actor' => { 'id' => user.id, 'login' => user.username },
'event' => 'reopened',
'created_at' => '2022-04-26 18:30:53 UTC',
'issue_db_id' => issue.id
@@ -42,6 +44,10 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::Reopened, :aggregate_fail
}.stringify_keys
end
+ before do
+ allow(user_finder).to receive(:find).with(user.id, user.username).and_return(user.id)
+ end
+
it 'creates expected event and state event' do
importer.execute(issue_event)
diff --git a/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb
index 41d777fb466..fee7c2708a4 100644
--- a/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab
specific_importer = double(importer_class.name) # rubocop:disable RSpec/VerifiedDoubles
expect(importer_class)
- .to receive(:new).with(project, user.id)
+ .to receive(:new).with(project, anything)
.and_return(specific_importer)
expect(specific_importer).to receive(:execute).with(issue_event)
@@ -43,12 +43,6 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab
describe '#execute' do
before do
- allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder|
- allow(finder).to receive(:author_id_for)
- .with(issue_event, author_key: :actor)
- .and_return(user.id, true)
- end
-
issue_event.attributes[:issue_db_id] = issue.id
end
@@ -108,6 +102,20 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueEventImporter, :clean_gitlab
Gitlab::GithubImport::Importer::Events::CrossReferenced
end
+ context "when it's assigned issue event" do
+ let(:event_name) { 'assigned' }
+
+ it_behaves_like 'triggers specific event importer',
+ Gitlab::GithubImport::Importer::Events::ChangedAssignee
+ end
+
+ context "when it's unassigned issue event" do
+ let(:event_name) { 'unassigned' }
+
+ it_behaves_like 'triggers specific event importer',
+ Gitlab::GithubImport::Importer::Events::ChangedAssignee
+ end
+
context "when it's unknown issue event" do
let(:event_name) { 'fake' }
diff --git a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
index 7382b0e2fff..cf796b55b14 100644
--- a/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
+++ b/spec/lib/gitlab/github_import/representation/issue_event_spec.rb
@@ -91,6 +91,29 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
end
end
+ context 'when assignee and assigner data is present' do
+ it 'includes assignee and assigner details' do
+ expect(issue_event.assignee)
+ .to be_an_instance_of(Gitlab::GithubImport::Representation::User)
+ expect(issue_event.assignee.id).to eq(5)
+ expect(issue_event.assignee.login).to eq('tom')
+
+ expect(issue_event.assigner)
+ .to be_an_instance_of(Gitlab::GithubImport::Representation::User)
+ expect(issue_event.assigner.id).to eq(6)
+ expect(issue_event.assigner.login).to eq('jerry')
+ end
+ end
+
+ context 'when assignee and assigner data is empty' do
+ let(:with_assignee) { false }
+
+ it 'does not return such info' do
+ expect(issue_event.assignee).to eq nil
+ expect(issue_event.assigner).to eq nil
+ end
+ end
+
it 'includes the created timestamp' do
expect(issue_event.created_at).to eq('2022-04-26 18:30:53 UTC')
end
@@ -106,8 +129,8 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
describe '.from_api_response' do
let(:response) do
event_resource = Struct.new(
- :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label,
- :rename, :milestone, :source, :issue_db_id, :created_at, :performed_via_github_app,
+ :id, :node_id, :url, :actor, :event, :commit_id, :commit_url, :label, :rename, :milestone,
+ :source, :assignee, :assigner, :issue_db_id, :created_at, :performed_via_github_app,
keyword_init: true
)
user_resource = Struct.new(:id, :login, keyword_init: true)
@@ -124,6 +147,8 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
rename: with_rename ? { from: 'old title', to: 'new title' } : nil,
milestone: with_milestone ? { title: 'milestone title' } : nil,
source: { type: 'issue', id: 123456 },
+ assignee: with_assignee ? user_resource.new(id: 5, login: 'tom') : nil,
+ assigner: with_assignee ? user_resource.new(id: 6, login: 'jerry') : nil,
issue_db_id: 100500,
created_at: '2022-04-26 18:30:53 UTC',
performed_via_github_app: nil
@@ -134,6 +159,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
let(:with_label) { true }
let(:with_rename) { true }
let(:with_milestone) { true }
+ let(:with_assignee) { true }
it_behaves_like 'an IssueEvent' do
let(:issue_event) { described_class.from_api_response(response) }
@@ -157,6 +183,8 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
'new_title' => with_rename ? 'new title' : nil,
'milestone_title' => (with_milestone ? 'milestone title' : nil),
'source' => { 'type' => 'issue', 'id' => 123456 },
+ 'assignee' => (with_assignee ? { 'id' => 5, 'login' => 'tom' } : nil),
+ 'assigner' => (with_assignee ? { 'id' => 6, 'login' => 'jerry' } : nil),
"issue_db_id" => 100500,
'created_at' => '2022-04-26 18:30:53 UTC',
'performed_via_github_app' => nil
@@ -167,6 +195,7 @@ RSpec.describe Gitlab::GithubImport::Representation::IssueEvent do
let(:with_label) { true }
let(:with_rename) { true }
let(:with_milestone) { true }
+ let(:with_assignee) { true }
let(:issue_event) { described_class.from_json_hash(hash) }
end
diff --git a/spec/lib/gitlab/github_import/user_finder_spec.rb b/spec/lib/gitlab/github_import/user_finder_spec.rb
index 8eb6eedd72d..d85e298785c 100644
--- a/spec/lib/gitlab/github_import/user_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/user_finder_spec.rb
@@ -15,32 +15,64 @@ RSpec.describe Gitlab::GithubImport::UserFinder, :clean_gitlab_redis_cache do
let(:finder) { described_class.new(project, client) }
describe '#author_id_for' do
- it 'returns the user ID for the author of an object' do
- user = double(:user, id: 4, login: 'kittens')
- note = double(:note, author: user)
+ context 'with default author_key' do
+ it 'returns the user ID for the author of an object' do
+ user = double(:user, id: 4, login: 'kittens')
+ note = double(:note, author: user)
- expect(finder).to receive(:user_id_for).with(user).and_return(42)
+ expect(finder).to receive(:user_id_for).with(user).and_return(42)
- expect(finder.author_id_for(note)).to eq([42, true])
- end
+ expect(finder.author_id_for(note)).to eq([42, true])
+ end
- it 'returns the ID of the project creator if no user ID could be found' do
- user = double(:user, id: 4, login: 'kittens')
- note = double(:note, author: user)
+ it 'returns the ID of the project creator if no user ID could be found' do
+ user = double(:user, id: 4, login: 'kittens')
+ note = double(:note, author: user)
- expect(finder).to receive(:user_id_for).with(user).and_return(nil)
+ expect(finder).to receive(:user_id_for).with(user).and_return(nil)
- expect(finder.author_id_for(note)).to eq([project.creator_id, false])
- end
+ expect(finder.author_id_for(note)).to eq([project.creator_id, false])
+ end
+
+ it 'returns the ID of the ghost user when the object has no user' do
+ note = double(:note, author: nil)
- it 'returns the ID of the ghost user when the object has no user' do
- note = double(:note, author: nil)
+ expect(finder.author_id_for(note)).to eq([User.ghost.id, true])
+ end
- expect(finder.author_id_for(note)).to eq([User.ghost.id, true])
+ it 'returns the ID of the ghost user when the given object is nil' do
+ expect(finder.author_id_for(nil)).to eq([User.ghost.id, true])
+ end
end
- it 'returns the ID of the ghost user when the given object is nil' do
- expect(finder.author_id_for(nil)).to eq([User.ghost.id, true])
+ context 'with a non-default author_key' do
+ let(:user) { double(:user, id: 4, login: 'kittens') }
+
+ shared_examples 'user ID finder' do |author_key|
+ it 'returns the user ID for an object' do
+ expect(finder).to receive(:user_id_for).with(user).and_return(42)
+
+ expect(finder.author_id_for(issue_event, author_key: author_key)).to eq([42, true])
+ end
+ end
+
+ context 'when the author_key parameter is :actor' do
+ let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', actor: user) }
+
+ it_behaves_like 'user ID finder', :actor
+ end
+
+ context 'when the author_key parameter is :assignee' do
+ let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assignee: user) }
+
+ it_behaves_like 'user ID finder', :assignee
+ end
+
+ context 'when the author_key parameter is :assigner' do
+ let(:issue_event) { double('Gitlab::GithubImport::Representation::IssueEvent', assigner: user) }
+
+ it_behaves_like 'user ID finder', :assigner
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_saver_spec.rb b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb
new file mode 100644
index 00000000000..dec51b3afd1
--- /dev/null
+++ b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ImportExport::Project::RelationSaver do
+ include ImportExport::CommonUtil
+
+ subject(:relation_saver) { described_class.new(project: project, shared: shared, relation: relation) }
+
+ let_it_be(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let_it_be(:project) { setup_project }
+
+ let(:relation) { Projects::ImportExport::RelationExport::ROOT_RELATION }
+ let(:shared) do
+ shared = project.import_export_shared
+ allow(shared).to receive(:export_path).and_return(export_path)
+ shared
+ end
+
+ after do
+ FileUtils.rm_rf(export_path)
+ end
+
+ describe '#save' do
+ context 'when relation is the root node' do
+ let(:relation) { Projects::ImportExport::RelationExport::ROOT_RELATION }
+
+ it 'serializes the root node as a json file in the export path' do
+ relation_saver.save # rubocop:disable Rails/SaveBang
+
+ json = read_json(File.join(shared.export_path, 'project.json'))
+ expect(json).to include({ 'description' => 'Project description' })
+ end
+
+ it 'serializes only allowed attributes' do
+ relation_saver.save # rubocop:disable Rails/SaveBang
+
+ json = read_json(File.join(shared.export_path, 'project.json'))
+ expect(json).to include({ 'description' => 'Project description' })
+ expect(json.keys).not_to include('name')
+ end
+
+ it 'successfuly serializes without errors' do
+ result = relation_saver.save # rubocop:disable Rails/SaveBang
+
+ expect(result).to eq(true)
+ expect(shared.errors).to be_empty
+ end
+ end
+
+ context 'when relation is a child node' do
+ let(:relation) { 'labels' }
+
+ it 'serializes the child node as a ndjson file in the export path inside the project folder' do
+ relation_saver.save # rubocop:disable Rails/SaveBang
+
+ ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson"))
+ expect(ndjson.first).to include({ 'title' => 'Label 1' })
+ expect(ndjson.second).to include({ 'title' => 'Label 2' })
+ end
+
+ it 'serializes only allowed attributes' do
+ relation_saver.save # rubocop:disable Rails/SaveBang
+
+ ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson"))
+ expect(ndjson.first.keys).not_to include('description_html')
+ end
+
+ it 'successfuly serializes without errors' do
+ result = relation_saver.save # rubocop:disable Rails/SaveBang
+
+ expect(result).to eq(true)
+ expect(shared.errors).to be_empty
+ end
+ end
+
+ context 'when relation name is not supported' do
+ let(:relation) { 'unknown' }
+
+ it 'returns false and register the error' do
+ result = relation_saver.save # rubocop:disable Rails/SaveBang
+
+ expect(result).to eq(false)
+ expect(shared.errors).to be_present
+ end
+ end
+
+ context 'when an exception occurs during serialization' do
+ it 'returns false and register the exception error message' do
+ allow_next_instance_of(Gitlab::ImportExport::Json::StreamingSerializer) do |serializer|
+ allow(serializer).to receive(:serialize_root).and_raise('Error!')
+ end
+
+ result = relation_saver.save # rubocop:disable Rails/SaveBang
+
+ expect(result).to eq(false)
+ expect(shared.errors).to include('Error!')
+ end
+ end
+ end
+
+ def setup_project
+ project = create(:project,
+ description: 'Project description'
+ )
+
+ create(:label, project: project, title: 'Label 1')
+ create(:label, project: project, title: 'Label 2')
+
+ project
+ end
+
+ def read_json(path)
+ Gitlab::Json.parse(IO.read(path))
+ end
+
+ def read_ndjson(path)
+ relations = []
+ File.foreach(path) do |line|
+ json = Gitlab::Json.parse(line)
+ relations << json
+ end
+ relations
+ end
+end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index fa03c6920c6..26883fc57b8 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -856,16 +856,6 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
it 'returns the successful deployment jobs for the last deployment pipeline' do
expect(subject.pluck(:id)).to contain_exactly(deployment_a.id, deployment_b.id)
end
-
- context 'when the feature flag is disabled' do
- before do
- stub_feature_flags(batch_load_environment_last_deployment_group: false)
- end
-
- it 'returns the successful deployment jobs for the last deployment pipeline' do
- expect(subject.pluck(:id)).to contain_exactly(deployment_a.id, deployment_b.id)
- end
- end
end
end
diff --git a/spec/models/projects/import_export/relation_export_spec.rb b/spec/models/projects/import_export/relation_export_spec.rb
index c74ca82e161..8643fbc7b46 100644
--- a/spec/models/projects/import_export/relation_export_spec.rb
+++ b/spec/models/projects/import_export/relation_export_spec.rb
@@ -20,4 +20,36 @@ RSpec.describe Projects::ImportExport::RelationExport, type: :model do
it { is_expected.to validate_length_of(:jid).is_at_most(255) }
it { is_expected.to validate_length_of(:export_error).is_at_most(300) }
end
+
+ describe '.by_relation' do
+ it 'returns export relations filtered by relation name' do
+ project_relation_export_1 = create(:project_relation_export, relation: 'labels')
+ project_relation_export_2 = create(:project_relation_export, relation: 'labels')
+ create(:project_relation_export, relation: 'uploads')
+
+ relations = described_class.by_relation('labels').to_a
+
+ expect(relations).to match_array([project_relation_export_1, project_relation_export_2])
+ end
+ end
+
+ describe '.relation_names_list' do
+ it 'includes extra relations list' do
+ expect(described_class.relation_names_list).to include(
+ 'design_repository', 'lfs_objects', 'repository', 'snippets_repository', 'uploads', 'wiki_repository'
+ )
+ end
+
+ it 'includes root tree relation name project' do
+ expect(described_class.relation_names_list).to include('project')
+ end
+
+ it 'includes project tree top level relation nodes' do
+ expect(described_class.relation_names_list).to include('milestones', 'issues', 'snippets', 'releases')
+ end
+
+ it 'includes project tree nested relation nodes' do
+ expect(described_class.relation_names_list).not_to include('events', 'notes')
+ end
+ end
end
diff --git a/spec/services/projects/import_export/relation_export_service_spec.rb b/spec/services/projects/import_export/relation_export_service_spec.rb
new file mode 100644
index 00000000000..94f5653ee7d
--- /dev/null
+++ b/spec/services/projects/import_export/relation_export_service_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::RelationExportService do
+ using RSpec::Parameterized::TableSyntax
+
+ subject(:service) { described_class.new(relation_export, 'jid') }
+
+ let_it_be(:project_export_job) { create(:project_export_job) }
+ let_it_be(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let_it_be(:archive_path) { "#{Dir.tmpdir}/project_archive_spec" }
+
+ let(:relation_export) { create(:project_relation_export, relation: relation, project_export_job: project_export_job) }
+
+ before do
+ stub_uploads_object_storage(ImportExportUploader, enabled: false)
+
+ allow(project_export_job.project.import_export_shared).to receive(:export_path).and_return(export_path)
+ allow(project_export_job.project.import_export_shared).to receive(:archive_path).and_return(archive_path)
+ allow(FileUtils).to receive(:remove_entry).with(any_args).and_call_original
+ end
+
+ describe '#execute' do
+ let(:relation) { 'labels' }
+
+ it 'removes temporary paths used to export files' do
+ expect(FileUtils).to receive(:remove_entry).with(export_path)
+ expect(FileUtils).to receive(:remove_entry).with(archive_path)
+
+ service.execute
+ end
+
+ context 'when saver fails to export relation' do
+ before do
+ allow_next_instance_of(Gitlab::ImportExport::Project::RelationSaver) do |saver|
+ allow(saver).to receive(:save).and_return(false)
+ end
+ end
+
+ it 'flags export as failed' do
+ service.execute
+
+ expect(relation_export.failed?).to eq(true)
+ end
+
+ it 'logs failed message' do
+ expect_next_instance_of(Gitlab::Export::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ export_error: '',
+ message: 'Project relation export failed',
+ project_export_job_id: project_export_job.id,
+ project_id: project_export_job.project.id,
+ project_name: project_export_job.project.name
+ )
+ end
+
+ service.execute
+ end
+ end
+
+ context 'when an exception is raised' do
+ before do
+ allow_next_instance_of(Gitlab::ImportExport::Project::RelationSaver) do |saver|
+ allow(saver).to receive(:save).and_raise('Error!')
+ end
+ end
+
+ it 'flags export as failed' do
+ service.execute
+
+ expect(relation_export.failed?).to eq(true)
+ expect(relation_export.export_error).to eq('Error!')
+ end
+
+ it 'logs exception error message' do
+ expect_next_instance_of(Gitlab::Export::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ export_error: 'Error!',
+ message: 'Project relation export failed',
+ project_export_job_id: project_export_job.id,
+ project_id: project_export_job.project.id,
+ project_name: project_export_job.project.name
+ )
+ end
+
+ service.execute
+ end
+ end
+
+ describe 'relation name and saver class' do
+ where(:relation_name, :saver) do
+ Projects::ImportExport::RelationExport::UPLOADS_RELATION | Gitlab::ImportExport::UploadsSaver
+ Projects::ImportExport::RelationExport::REPOSITORY_RELATION | Gitlab::ImportExport::RepoSaver
+ Projects::ImportExport::RelationExport::WIKI_REPOSITORY_RELATION | Gitlab::ImportExport::WikiRepoSaver
+ Projects::ImportExport::RelationExport::LFS_OBJECTS_RELATION | Gitlab::ImportExport::LfsSaver
+ Projects::ImportExport::RelationExport::SNIPPETS_REPOSITORY_RELATION | Gitlab::ImportExport::SnippetsRepoSaver
+ Projects::ImportExport::RelationExport::DESIGN_REPOSITORY_RELATION | Gitlab::ImportExport::DesignRepoSaver
+ Projects::ImportExport::RelationExport::ROOT_RELATION | Gitlab::ImportExport::Project::RelationSaver
+ 'labels' | Gitlab::ImportExport::Project::RelationSaver
+ end
+
+ with_them do
+ let(:relation) { relation_name }
+
+ it 'exports relation using correct saver' do
+ expect(saver).to receive(:new).and_call_original
+
+ service.execute
+ end
+
+ it 'assigns finished status and relation file' do
+ service.execute
+
+ expect(relation_export.finished?).to eq(true)
+ expect(relation_export.upload.export_file.filename).to eq("#{relation}.tar.gz")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/security/ci_configuration/sast_parser_service_spec.rb b/spec/services/security/ci_configuration/sast_parser_service_spec.rb
index 4346d0a9e07..b11f31a9086 100644
--- a/spec/services/security/ci_configuration/sast_parser_service_spec.rb
+++ b/spec/services/security/ci_configuration/sast_parser_service_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe Security::CiConfiguration::SastParserService do
let(:bandit) { configuration['analyzers'][0] }
let(:brakeman) { configuration['analyzers'][1] }
let(:sast_brakeman_level) { brakeman['variables'][0] }
+ let(:secure_analyzers_prefix) { '$TEMPLATE_REGISTRY_HOST/security-products' }
it 'parses the configuration for SAST' do
expect(secure_analyzers['default_value']).to eql(secure_analyzers_prefix)
diff --git a/spec/services/work_items/create_and_link_service_spec.rb b/spec/services/work_items/create_and_link_service_spec.rb
index 831af775101..e259a22d388 100644
--- a/spec/services/work_items/create_and_link_service_spec.rb
+++ b/spec/services/work_items/create_and_link_service_spec.rb
@@ -62,6 +62,8 @@ RSpec.describe WorkItems::CreateAndLinkService do
)
end
+ it_behaves_like 'title with extra spaces'
+
context 'when link params are valid' do
let(:link_params) { { parent_work_item: related_work_item } }
diff --git a/spec/services/work_items/create_from_task_service_spec.rb b/spec/services/work_items/create_from_task_service_spec.rb
index 7d2dab228b1..7c5430f038c 100644
--- a/spec/services/work_items/create_from_task_service_spec.rb
+++ b/spec/services/work_items/create_from_task_service_spec.rb
@@ -64,6 +64,8 @@ RSpec.describe WorkItems::CreateFromTaskService do
expect(list_work_item.description).to eq("- [ ] #{created_work_item.to_reference}+")
end
+
+ it_behaves_like 'title with extra spaces'
end
context 'when last operation fails' do
diff --git a/spec/support/helpers/ci/template_helpers.rb b/spec/support/helpers/ci/template_helpers.rb
index 598a5a0becc..119f8d001a1 100644
--- a/spec/support/helpers/ci/template_helpers.rb
+++ b/spec/support/helpers/ci/template_helpers.rb
@@ -5,6 +5,10 @@ module Ci
def secure_analyzers_prefix
'registry.gitlab.com/security-products'
end
+
+ def template_registry_host
+ 'registry.gitlab.com'
+ end
end
end
diff --git a/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb b/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb
new file mode 100644
index 00000000000..7771e7f0e21
--- /dev/null
+++ b/spec/support/shared_examples/services/work_items/create_task_shared_examples.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'title with extra spaces' do
+ context 'when title has extra spaces' do
+ before do
+ params[:title] = " Awesome work item "
+ end
+
+ it 'removes extra leading and trailing whitespaces from title' do
+ subject
+
+ created_work_item = WorkItem.last
+ expect(created_work_item.title).to eq('Awesome work item')
+ end
+ end
+end
diff --git a/spec/workers/projects/import_export/relation_export_worker_spec.rb b/spec/workers/projects/import_export/relation_export_worker_spec.rb
new file mode 100644
index 00000000000..236650fe55b
--- /dev/null
+++ b/spec/workers/projects/import_export/relation_export_worker_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::ImportExport::RelationExportWorker, type: :worker do
+ let(:project_relation_export) { create(:project_relation_export) }
+ let(:job_args) { [project_relation_export.id] }
+
+ it_behaves_like 'an idempotent worker'
+
+ describe '#perform' do
+ subject(:worker) { described_class.new }
+
+ context 'when relation export has initial state queued' do
+ let(:project_relation_export) { create(:project_relation_export) }
+
+ it 'calls RelationExportService' do
+ expect_next_instance_of(Projects::ImportExport::RelationExportService) do |service|
+ expect(service).to receive(:execute)
+ end
+
+ worker.perform(project_relation_export.id)
+ end
+ end
+
+ context 'when relation export does not have queued state' do
+ let(:project_relation_export) { create(:project_relation_export, status_event: :start) }
+
+ it 'does not call RelationExportService' do
+ expect(Projects::ImportExport::RelationExportService).not_to receive(:new)
+
+ worker.perform(project_relation_export.id)
+ end
+ end
+ end
+end