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>2023-08-08 15:07:09 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-08 15:07:09 +0300
commite44c3e4832e43c77e9c29fad6e49f8d6066d7f5c (patch)
tree892f4505093dd5ffd60e238a8b74b35f021654ae /spec
parentaa1c2a29b8ddc82141f826eacd169d3d7ff66611 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/projects/settings/secure_files_spec.rb2
-rw-r--r--spec/frontend/super_sidebar/components/context_switcher_spec.js17
-rw-r--r--spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js65
-rw-r--r--spec/frontend/super_sidebar/components/global_search/mock_data.js18
-rw-r--r--spec/frontend/super_sidebar/components/global_search/store/getters_spec.js149
-rw-r--r--spec/frontend/super_sidebar/mock_data.js6
-rw-r--r--spec/graphql/types/ci/detailed_status_type_spec.rb2
-rw-r--r--spec/helpers/sidebars_helper_spec.rb26
-rw-r--r--spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/stage/play_manual_spec.rb4
-rw-r--r--spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb20
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/ci/runner_manager_spec.rb10
-rw-r--r--spec/models/ci/stage_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb139
-rw-r--r--spec/serializers/stage_entity_spec.rb6
-rw-r--r--spec/support/shared_examples/ci/stage_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/helpers/super_sidebar_shared_examples.rb2
-rw-r--r--spec/tooling/danger/stable_branch_spec.rb18
20 files changed, 336 insertions, 160 deletions
diff --git a/spec/features/projects/settings/secure_files_spec.rb b/spec/features/projects/settings/secure_files_spec.rb
index 7ff1a5f3568..5f94e215a5f 100644
--- a/spec/features/projects/settings/secure_files_spec.rb
+++ b/spec/features/projects/settings/secure_files_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'Secure Files', :js, feature_category: :groups_and_projects do
within '#js-secure-files' do
expect(page).to have_content(file.name)
- find('button.btn-danger-secondary').click
+ find('[data-testid="delete-button"]').click
end
expect(page).to have_content("Delete #{file.name}?")
diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js
index 4317f451377..dd8f39e7cb7 100644
--- a/spec/frontend/super_sidebar/components/context_switcher_spec.js
+++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js
@@ -15,7 +15,7 @@ import { trackContextAccess, formatContextSwitcherItems } from '~/super_sidebar/
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import waitForPromises from 'helpers/wait_for_promises';
import { stubComponent } from 'helpers/stub_component';
-import { searchUserProjectsAndGroupsResponseMock } from '../mock_data';
+import { contextSwitcherLinks, searchUserProjectsAndGroupsResponseMock } from '../mock_data';
jest.mock('~/super_sidebar/utils', () => ({
getStorageKeyFor: jest.requireActual('~/super_sidebar/utils').getStorageKeyFor,
@@ -26,9 +26,6 @@ jest.mock('~/super_sidebar/utils', () => ({
}));
const focusInputMock = jest.fn();
-const persistentLinks = [
- { title: 'Explore', link: '/explore', icon: 'compass', link_classes: 'persistent-link-class' },
-];
const username = 'root';
const projectsPath = 'projectsPath';
const groupsPath = 'groupsPath';
@@ -71,8 +68,10 @@ describe('ContextSwitcher component', () => {
wrapper = shallowMountExtended(ContextSwitcher, {
apolloProvider: mockApollo,
+ provide: {
+ contextSwitcherLinks,
+ },
propsData: {
- persistentLinks,
username,
projectsPath,
groupsPath,
@@ -107,14 +106,14 @@ describe('ContextSwitcher component', () => {
createWrapper();
});
- it('renders the persistent links', () => {
+ it('renders the context switcher links', () => {
const navItems = findNavItems();
const firstNavItem = navItems.at(0);
- expect(navItems.length).toBe(persistentLinks.length);
- expect(firstNavItem.props('item')).toBe(persistentLinks[0]);
+ expect(navItems.length).toBe(contextSwitcherLinks.length);
+ expect(firstNavItem.props('item')).toBe(contextSwitcherLinks[0]);
expect(firstNavItem.props('linkClasses')).toEqual({
- [persistentLinks[0].link_classes]: persistentLinks[0].link_classes,
+ [contextSwitcherLinks[0].link_classes]: contextSwitcherLinks[0].link_classes,
});
});
diff --git a/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js
index 52e9aa52c14..0fb6585e8ca 100644
--- a/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/components/global_search_default_items_spec.js
@@ -4,36 +4,42 @@ import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import GlobalSearchDefaultItems from '~/super_sidebar/components/global_search/components/global_search_default_items.vue';
import { MOCK_SEARCH_CONTEXT, MOCK_DEFAULT_SEARCH_OPTIONS } from '../mock_data';
+import { contextSwitcherLinks } from '../../../mock_data';
Vue.use(Vuex);
describe('GlobalSearchDefaultItems', () => {
let wrapper;
- const createComponent = (initialState, props) => {
+ const createComponent = ({
+ storeState,
+ mockDefaultSearchOptions = MOCK_DEFAULT_SEARCH_OPTIONS,
+ ...options
+ } = {}) => {
const store = new Vuex.Store({
state: {
searchContext: MOCK_SEARCH_CONTEXT,
- ...initialState,
+ ...storeState,
},
getters: {
- defaultSearchOptions: () => MOCK_DEFAULT_SEARCH_OPTIONS,
+ defaultSearchOptions: () => mockDefaultSearchOptions,
},
});
wrapper = shallowMountExtended(GlobalSearchDefaultItems, {
store,
- propsData: {
- ...props,
+ provide: {
+ contextSwitcherLinks,
},
stubs: {
GlDisclosureDropdownGroup,
},
+ ...options,
});
};
- const findItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
- const findItemsData = () => findItems().wrappers.map((w) => w.props('item'));
+ const findGroups = () => wrapper.findAllComponents(GlDisclosureDropdownGroup);
+ const findItems = (root = wrapper) => root.findAllComponents(GlDisclosureDropdownItem);
describe('template', () => {
describe('Dropdown items', () => {
@@ -41,12 +47,39 @@ describe('GlobalSearchDefaultItems', () => {
createComponent();
});
- it('renders item for each option in defaultSearchOptions', () => {
- expect(findItems()).toHaveLength(MOCK_DEFAULT_SEARCH_OPTIONS.length);
+ it('renders two groups', () => {
+ const groups = findGroups();
+
+ expect(groups).toHaveLength(2);
+
+ const actualNames = groups.wrappers.map((group) => group.props('group').name);
+ expect(actualNames).toEqual(['Places', 'All GitLab']);
+ });
+
+ it('renders context switcher links in first group', () => {
+ const group = findGroups().at(0);
+ expect(group.props('group').name).toBe('Places');
+
+ const items = findItems(group);
+ expect(items).toHaveLength(contextSwitcherLinks.length);
+ });
+
+ it('renders default search options in second group', () => {
+ const group = findGroups().at(1);
+ expect(group.props('group').name).toBe('All GitLab');
+
+ const items = findItems(group);
+ expect(items).toHaveLength(MOCK_DEFAULT_SEARCH_OPTIONS.length);
+ });
+ });
+
+ describe('Empty groups', () => {
+ beforeEach(() => {
+ createComponent({ mockDefaultSearchOptions: [], provide: { contextSwitcherLinks: [] } });
});
- it('provides the `item` prop to the `GlDisclosureDropdownItem` component', () => {
- expect(findItemsData()).toStrictEqual(MOCK_DEFAULT_SEARCH_OPTIONS);
+ it('does not render groups with no items', () => {
+ expect(findGroups()).toHaveLength(0);
});
});
@@ -55,13 +88,15 @@ describe('GlobalSearchDefaultItems', () => {
${null} | ${null} | ${'All GitLab'}
${{ name: 'Test Group' }} | ${null} | ${'Test Group'}
${{ name: 'Test Group' }} | ${{ name: 'Test Project' }} | ${'Test Project'}
- `('Group Header', ({ group, project, groupHeader }) => {
+ `('Current context header', ({ group, project, groupHeader }) => {
describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
beforeEach(() => {
createComponent({
- searchContext: {
- group,
- project,
+ storeState: {
+ searchContext: {
+ group,
+ project,
+ },
},
});
});
diff --git a/spec/frontend/super_sidebar/components/global_search/mock_data.js b/spec/frontend/super_sidebar/components/global_search/mock_data.js
index ad7e7b0b30b..dfa8b458844 100644
--- a/spec/frontend/super_sidebar/components/global_search/mock_data.js
+++ b/spec/frontend/super_sidebar/components/global_search/mock_data.js
@@ -62,6 +62,24 @@ export const MOCK_SEARCH_CONTEXT = {
group_metadata: {},
};
+export const MOCK_GROUP_SEARCH_CONTEXT = {
+ ...MOCK_SEARCH_CONTEXT,
+ group: MOCK_GROUP,
+ group_metadata: {
+ issues_path: `${MOCK_GROUP.path}/issues`,
+ mr_path: `${MOCK_GROUP.path}/merge_requests`,
+ },
+};
+
+export const MOCK_PROJECT_SEARCH_CONTEXT = {
+ ...MOCK_GROUP_SEARCH_CONTEXT,
+ project: MOCK_PROJECT,
+ project_metadata: {
+ issues_path: `${MOCK_PROJECT.path}/issues`,
+ mr_path: `${MOCK_PROJECT.path}/merge_requests`,
+ },
+};
+
export const MOCK_DEFAULT_SEARCH_OPTIONS = [
{
text: MSG_ISSUES_ASSIGNED_TO_ME,
diff --git a/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js
index 68583d04b31..de636d1feec 100644
--- a/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/store/getters_spec.js
@@ -7,6 +7,8 @@ import {
MOCK_MR_PATH,
MOCK_AUTOCOMPLETE_PATH,
MOCK_SEARCH_CONTEXT,
+ MOCK_GROUP_SEARCH_CONTEXT,
+ MOCK_PROJECT_SEARCH_CONTEXT,
MOCK_DEFAULT_SEARCH_OPTIONS,
MOCK_SCOPED_SEARCH_OPTIONS,
MOCK_SCOPED_SEARCH_GROUP,
@@ -74,37 +76,47 @@ describe('Global Search Store Getters', () => {
});
describe.each`
- group | group_metadata | project | project_metadata | expectedPath
- ${null} | ${null} | ${null} | ${null} | ${MOCK_ISSUE_PATH}
- ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${null} | ${null} | ${'group/path'}
- ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${{ name: 'Test Project' }} | ${{ issues_path: 'project/path' }} | ${'project/path'}
- `('scopedIssuesPath', ({ group, group_metadata, project, project_metadata, expectedPath }) => {
- describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
- beforeEach(() => {
- createState({
- searchContext: {
- group,
- group_metadata,
- project,
- project_metadata,
- },
+ group | group_metadata | project | project_metadata | user | expectedPath
+ ${null} | ${null} | ${null} | ${null} | ${'a_user'} | ${MOCK_ISSUE_PATH}
+ ${null} | ${null} | ${null} | ${null} | ${null} | ${false}
+ ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${null} | ${null} | ${null} | ${'group/path'}
+ ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${{ id: '123' }} | ${{ issues_path: 'project/path' }} | ${null} | ${'project/path'}
+ ${{ name: 'Test Group' }} | ${{ issues_path: 'group/path' }} | ${{ id: '123' }} | ${{}} | ${null} | ${false}
+ `(
+ 'scopedIssuesPath',
+ ({ group, group_metadata, project, project_metadata, user, expectedPath }) => {
+ describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ beforeEach(() => {
+ window.gon.current_username = user;
+
+ createState({
+ searchContext: {
+ group,
+ group_metadata,
+ project,
+ project_metadata,
+ },
+ });
});
- });
- it(`should return ${expectedPath}`, () => {
- expect(getters.scopedIssuesPath(state)).toBe(expectedPath);
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.scopedIssuesPath(state)).toBe(expectedPath);
+ });
});
- });
- });
+ },
+ );
describe.each`
- group | group_metadata | project | project_metadata | expectedPath
- ${null} | ${null} | ${null} | ${null} | ${MOCK_MR_PATH}
- ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${null} | ${null} | ${'group/path'}
- ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${{ name: 'Test Project' }} | ${{ mr_path: 'project/path' }} | ${'project/path'}
- `('scopedMRPath', ({ group, group_metadata, project, project_metadata, expectedPath }) => {
+ group | group_metadata | project | project_metadata | user | expectedPath
+ ${null} | ${null} | ${null} | ${null} | ${'a_user'} | ${MOCK_MR_PATH}
+ ${null} | ${null} | ${null} | ${null} | ${null} | ${false}
+ ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${null} | ${null} | ${null} | ${'group/path'}
+ ${{ name: 'Test Group' }} | ${{ mr_path: 'group/path' }} | ${{ name: 'Test Project' }} | ${{ mr_path: 'project/path' }} | ${null} | ${'project/path'}
+ `('scopedMRPath', ({ group, group_metadata, project, project_metadata, user, expectedPath }) => {
describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
beforeEach(() => {
+ window.gon.current_username = user;
+
createState({
searchContext: {
group,
@@ -227,27 +239,88 @@ describe('Global Search Store Getters', () => {
});
describe('defaultSearchOptions', () => {
- const mockGetters = {
- scopedIssuesPath: MOCK_ISSUE_PATH,
- scopedMRPath: MOCK_MR_PATH,
- };
+ let mockGetters;
beforeEach(() => {
createState();
- window.gon.current_username = MOCK_USERNAME;
+ mockGetters = {
+ scopedIssuesPath: MOCK_ISSUE_PATH,
+ scopedMRPath: MOCK_MR_PATH,
+ };
});
- it('returns the correct array', () => {
- expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
- MOCK_DEFAULT_SEARCH_OPTIONS,
- );
+ describe('with a user', () => {
+ beforeEach(() => {
+ window.gon.current_username = MOCK_USERNAME;
+ });
+
+ it('returns the correct array', () => {
+ expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_DEFAULT_SEARCH_OPTIONS,
+ );
+ });
+
+ it('returns the correct array if issues path is false', () => {
+ mockGetters.scopedIssuesPath = undefined;
+ expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
+ MOCK_DEFAULT_SEARCH_OPTIONS.slice(2, MOCK_DEFAULT_SEARCH_OPTIONS.length),
+ );
+ });
});
- it('returns the correct array if issues path is false', () => {
- mockGetters.scopedIssuesPath = undefined;
- expect(getters.defaultSearchOptions(state, mockGetters)).toStrictEqual(
- MOCK_DEFAULT_SEARCH_OPTIONS.slice(2, MOCK_DEFAULT_SEARCH_OPTIONS.length),
- );
+ describe('without a user', () => {
+ describe('with no project or group context', () => {
+ beforeEach(() => {
+ mockGetters = {
+ scopedIssuesPath: false,
+ scopedMRPath: false,
+ };
+ });
+
+ it('returns an empty array', () => {
+ expect(getters.defaultSearchOptions(state, mockGetters)).toEqual([]);
+ });
+ });
+
+ describe('with a group context', () => {
+ beforeEach(() => {
+ createState({
+ searchContext: MOCK_GROUP_SEARCH_CONTEXT,
+ });
+
+ mockGetters = {
+ scopedIssuesPath: state.searchContext.group_metadata.issues_path,
+ scopedMRPath: state.searchContext.group_metadata.mr_path,
+ };
+ });
+
+ it('returns recent issues/merge requests options', () => {
+ expect(getters.defaultSearchOptions(state, mockGetters)).toEqual([
+ { href: '/mock-group/issues', text: 'Recent issues' },
+ { href: '/mock-group/merge_requests', text: 'Recent merge requests' },
+ ]);
+ });
+ });
+
+ describe('with a project context', () => {
+ beforeEach(() => {
+ createState({
+ searchContext: MOCK_PROJECT_SEARCH_CONTEXT,
+ });
+
+ mockGetters = {
+ scopedIssuesPath: state.searchContext.project_metadata.issues_path,
+ scopedMRPath: state.searchContext.project_metadata.mr_path,
+ };
+ });
+
+ it('returns recent issues/merge requests options', () => {
+ expect(getters.defaultSearchOptions(state, mockGetters)).toEqual([
+ { href: '/mock-project/issues', text: 'Recent issues' },
+ { href: '/mock-project/merge_requests', text: 'Recent merge requests' },
+ ]);
+ });
+ });
});
});
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index df45360a898..0d34329c60d 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -71,6 +71,10 @@ export const mergeRequestMenuGroup = [
},
];
+export const contextSwitcherLinks = [
+ { title: 'Explore', link: '/explore', icon: 'compass', link_classes: 'persistent-link-class' },
+];
+
export const sidebarData = {
is_logged_in: true,
current_menu_items: [],
@@ -104,7 +108,7 @@ export const sidebarData = {
gitlab_version_check: { severity: 'success' },
gitlab_com_and_canary: false,
canary_toggle_com_url: 'https://next.gitlab.com',
- context_switcher_links: [],
+ context_switcher_links: contextSwitcherLinks,
search: {
search_path: '/search',
},
diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb
index 69fb2bc43c0..81ab1b52552 100644
--- a/spec/graphql/types/ci/detailed_status_type_spec.rb
+++ b/spec/graphql/types/ci/detailed_status_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Types::Ci::DetailedStatusType do
include GraphqlHelpers
- let_it_be(:stage) { create(:ci_stage, status: :manual) }
+ let_it_be(:stage) { create(:ci_stage, status: :skipped) }
specify { expect(described_class.graphql_name).to eq('DetailedStatus') }
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 3d675a65d99..4109eb01caa 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -374,11 +374,17 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
describe 'context switcher persistent links' do
let_it_be(:public_link) do
[
- { title: s_('Navigation|Your work'), link: '/', icon: 'work' },
{ title: s_('Navigation|Explore'), link: '/explore', icon: 'compass' }
]
end
+ let_it_be(:public_links_for_user) do
+ [
+ { title: s_('Navigation|Your work'), link: '/', icon: 'work' },
+ *public_link
+ ]
+ end
+
let_it_be(:admin_area_link) do
{ title: s_('Navigation|Admin Area'), link: '/admin', icon: 'admin' }
end
@@ -396,12 +402,20 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
helper.super_sidebar_context(user, group: nil, project: nil, panel: panel, panel_type: panel_type)
end
- context 'when user is not an admin' do
- it 'returns only the public links' do
+ context 'when user is not logged in' do
+ let(:user) { nil }
+
+ it 'returns only the public links for an anonymous user' do
expect(subject[:context_switcher_links]).to eq(public_link)
end
end
+ context 'when user is not an admin' do
+ it 'returns only the public links for a user' do
+ expect(subject[:context_switcher_links]).to eq(public_links_for_user)
+ end
+ end
+
context 'when user is an admin' do
before do
allow(user).to receive(:admin?).and_return(true)
@@ -420,7 +434,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
it 'returns public links, admin area and leave admin mode links' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
admin_area_link,
leave_admin_mode_link
])
@@ -430,7 +444,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
context 'when admin mode is off' do
it 'returns public links and enter admin mode link' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
enter_admin_mode_link
])
end
@@ -444,7 +458,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
it 'returns public links and admin area link' do
expect(subject[:context_switcher_links]).to eq([
- *public_link,
+ *public_links_for_user,
admin_area_link
])
end
diff --git a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
index 582c0fe1b1b..af8b5240e40 100644
--- a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
+++ b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveBackfilledJobArtifactsExpireAt
describe '#perform' do
let(:job_artifact) { table(:ci_job_artifacts, database: :ci) }
+ let(:jobs) { table(:ci_builds, database: :ci) { |model| model.primary_key = :id } }
let(:test_worker) do
described_class.new(
@@ -85,7 +86,7 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveBackfilledJobArtifactsExpireAt
private
def create_job_artifact(id:, file_type:, expire_at:)
- job = table(:ci_builds, database: :ci).create!(id: id, partition_id: 100)
+ job = jobs.create!(partition_id: 100)
job_artifact.create!(
id: id, job_id: job.id, expire_at: expire_at, project_id: project.id,
file_type: file_type, partition_id: 100
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 702341a7ea7..35d44281072 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Status::Stage::Factory, feature_category: :continuous_integration do
+RSpec.describe Gitlab::Ci::Status::Stage::Factory do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
@@ -62,7 +62,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::Factory, feature_category: :continuous
end
context 'when stage has manual builds' do
- Ci::HasStatus::BLOCKED_STATUS.each do |core_status|
+ (Ci::HasStatus::BLOCKED_STATUS + ['skipped']).each do |core_status|
context "when status is #{core_status}" do
let(:stage) { create(:ci_stage, pipeline: pipeline, status: core_status) }
diff --git a/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb b/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
index e23645c106b..9fdaddc083e 100644
--- a/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/play_manual_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Status::Stage::PlayManual, feature_category: :continuous_integration do
+RSpec.describe Gitlab::Ci::Status::Stage::PlayManual do
let(:stage) { double('stage') }
let(:play_manual) { described_class.new(stage) }
@@ -48,7 +48,7 @@ RSpec.describe Gitlab::Ci::Status::Stage::PlayManual, feature_category: :continu
context 'when stage is skipped' do
let(:stage) { create(:ci_stage, status: :skipped) }
- it { is_expected.to be_falsy }
+ it { is_expected.to be_truthy }
end
context 'when stage is manual' do
diff --git a/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb
index d03d4f64a0f..9fa24e5637f 100644
--- a/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb
+++ b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb
@@ -24,26 +24,6 @@ RSpec.describe Gitlab::Cleanup::OrphanJobArtifactFilesBatch do
expect(batch.lost_and_found.count).to eq(1)
expect(batch.lost_and_found.first.artifact_id).to eq(orphan_artifact.id)
end
-
- it 'does not mix up job ID and artifact ID' do
- # take maximum ID of both tables to avoid any collision
- max_id = [Ci::Build.maximum(:id), Ci::JobArtifact.maximum(:id)].compact.max.to_i
- job_a = create(:ci_build, id: max_id + 1)
- job_b = create(:ci_build, id: max_id + 2)
- # reuse the build IDs for the job artifact IDs, but swap them
- job_artifact_b = create(:ci_job_artifact, :archive, job: job_b, id: max_id + 1)
- job_artifact_a = create(:ci_job_artifact, :archive, job: job_a, id: max_id + 2)
-
- batch << artifact_path(job_artifact_a)
- batch << artifact_path(job_artifact_b)
-
- job_artifact_b.delete
-
- batch.clean!
-
- expect(File.exist?(job_artifact_a.file.path)).to be_truthy
- expect(File.exist?(job_artifact_b.file.path)).to be_falsey
- end
end
context 'with dry run' do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 641cc13adb7..6d01f480cd0 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -820,6 +820,7 @@ project:
- scan_result_policy_reads
- project_state
- security_policy_bots
+- target_branch_rules
award_emoji:
- awardable
- user
diff --git a/spec/models/ci/runner_manager_spec.rb b/spec/models/ci/runner_manager_spec.rb
index 575064f0bea..d69bf1a0da0 100644
--- a/spec/models/ci/runner_manager_spec.rb
+++ b/spec/models/ci/runner_manager_spec.rb
@@ -112,6 +112,16 @@ RSpec.describe Ci::RunnerManager, feature_category: :runner_fleet, type: :model
end
end
+ describe '.order_id_desc' do
+ subject(:scope) { described_class.order_id_desc }
+
+ let_it_be(:runner_manager1) { create(:ci_runner_machine) }
+ let_it_be(:runner_manager2) { create(:ci_runner_machine) }
+
+ specify { expect(described_class.all).to eq([runner_manager1, runner_manager2]) }
+ it { is_expected.to eq([runner_manager2, runner_manager1]) }
+ end
+
describe '#status', :freeze_time do
let(:runner_manager) { build(:ci_runner_machine, created_at: 8.days.ago) }
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index 1be50083cd4..79e92082ee1 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Stage, :models, feature_category: :continuous_integration do
+RSpec.describe Ci::Stage, :models do
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
let(:stage) { create(:ci_stage, pipeline: pipeline, project: pipeline.project) }
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index c8706ae9698..3f6d39435fd 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -34,67 +34,116 @@ RSpec.describe 'Query.runners', feature_category: :runner_fleet do
QUERY
end
- let(:query) do
- %(
- query {
- runners(type:#{runner_type},status:#{status}) {
- #{fields}
+ context 'with filters' do
+ let(:query) do
+ %(
+ query {
+ runners(type: #{runner_type}, status: #{status}) {
+ #{fields}
+ }
}
- }
- )
- end
-
- before do
- allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
- allow(instance).to receive(:check_runner_upgrade_suggestion)
+ )
end
- post_graphql(query, current_user: current_user)
- end
-
- shared_examples 'a working graphql query returning expected runner' do
- it_behaves_like 'a working graphql query'
+ before do
+ allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
+ allow(instance).to receive(:check_runner_upgrade_suggestion)
+ end
- it 'returns expected runner' do
- expect(runners_graphql_data['nodes']).to contain_exactly(a_graphql_entity_for(expected_runner))
+ post_graphql(query, current_user: current_user)
end
- it 'does not execute more queries per runner', :aggregate_failures do
- # warm-up license cache and so on:
- personal_access_token = create(:personal_access_token, user: current_user)
- args = { current_user: current_user, token: { personal_access_token: personal_access_token } }
- post_graphql(query, **args)
- expect(graphql_data_at(:runners, :nodes)).not_to be_empty
+ shared_examples 'a working graphql query returning expected runner' do
+ it_behaves_like 'a working graphql query'
+
+ it 'returns expected runner' do
+ expect(runners_graphql_data['nodes']).to contain_exactly(a_graphql_entity_for(expected_runner))
+ end
+
+ it 'does not execute more queries per runner', :aggregate_failures do
+ # warm-up license cache and so on:
+ personal_access_token = create(:personal_access_token, user: current_user)
+ args = { current_user: current_user, token: { personal_access_token: personal_access_token } }
+ post_graphql(query, **args)
+ expect(graphql_data_at(:runners, :nodes)).not_to be_empty
- admin2 = create(:admin)
- personal_access_token = create(:personal_access_token, user: admin2)
- args = { current_user: admin2, token: { personal_access_token: personal_access_token } }
- control = ActiveRecord::QueryRecorder.new { post_graphql(query, **args) }
+ admin2 = create(:admin)
+ personal_access_token = create(:personal_access_token, user: admin2)
+ args = { current_user: admin2, token: { personal_access_token: personal_access_token } }
+ control = ActiveRecord::QueryRecorder.new { post_graphql(query, **args) }
- create(:ci_runner, :instance, version: '14.0.0', tag_list: %w[tag5 tag6], creator: admin2)
- create(:ci_runner, :project, version: '14.0.1', projects: [project], tag_list: %w[tag3 tag8],
- creator: current_user)
+ create(:ci_runner, :instance, version: '14.0.0', tag_list: %w[tag5 tag6], creator: admin2)
+ create(:ci_runner, :project, version: '14.0.1', projects: [project], tag_list: %w[tag3 tag8],
+ creator: current_user)
- expect { post_graphql(query, **args) }.not_to exceed_query_limit(control)
+ expect { post_graphql(query, **args) }.not_to exceed_query_limit(control)
+ end
end
- end
- context 'runner_type is INSTANCE_TYPE and status is ACTIVE' do
- let(:runner_type) { 'INSTANCE_TYPE' }
- let(:status) { 'ACTIVE' }
+ context 'runner_type is INSTANCE_TYPE and status is ACTIVE' do
+ let(:runner_type) { 'INSTANCE_TYPE' }
+ let(:status) { 'ACTIVE' }
- let!(:expected_runner) { instance_runner }
+ let!(:expected_runner) { instance_runner }
- it_behaves_like 'a working graphql query returning expected runner'
- end
+ it_behaves_like 'a working graphql query returning expected runner'
+ end
- context 'runner_type is PROJECT_TYPE and status is NEVER_CONTACTED' do
- let(:runner_type) { 'PROJECT_TYPE' }
- let(:status) { 'NEVER_CONTACTED' }
+ context 'runner_type is PROJECT_TYPE and status is NEVER_CONTACTED' do
+ let(:runner_type) { 'PROJECT_TYPE' }
+ let(:status) { 'NEVER_CONTACTED' }
- let!(:expected_runner) { project_runner }
+ let!(:expected_runner) { project_runner }
+
+ it_behaves_like 'a working graphql query returning expected runner'
+ end
+ end
- it_behaves_like 'a working graphql query returning expected runner'
+ context 'without filters' do
+ context 'with managers requested for multiple runners' do
+ let(:fields) do
+ <<~QUERY
+ nodes {
+ managers {
+ nodes {
+ #{all_graphql_fields_for('CiRunnerManager', max_depth: 1)}
+ }
+ }
+ }
+ QUERY
+ end
+
+ let(:query) do
+ %(
+ query {
+ runners {
+ #{fields}
+ }
+ }
+ )
+ end
+
+ it 'does not execute more queries per runner', :aggregate_failures do
+ # warm-up license cache and so on:
+ personal_access_token = create(:personal_access_token, user: current_user)
+ args = { current_user: current_user, token: { personal_access_token: personal_access_token } }
+ post_graphql(query, **args)
+ expect(graphql_data_at(:runners, :nodes)).not_to be_empty
+
+ admin2 = create(:admin)
+ personal_access_token = create(:personal_access_token, user: admin2)
+ args = { current_user: admin2, token: { personal_access_token: personal_access_token } }
+ control = ActiveRecord::QueryRecorder.new { post_graphql(query, **args) }
+
+ create(:ci_runner, :instance, :with_runner_manager, version: '14.0.0', tag_list: %w[tag5 tag6],
+ creator: admin2)
+ create(:ci_runner, :project, :with_runner_manager, version: '14.0.1', projects: [project],
+ tag_list: %w[tag3 tag8],
+ creator: current_user)
+
+ expect { post_graphql(query, **args) }.not_to exceed_query_limit(control)
+ end
+ end
end
end
diff --git a/spec/serializers/stage_entity_spec.rb b/spec/serializers/stage_entity_spec.rb
index fe8ee027245..5cb5724ebdc 100644
--- a/spec/serializers/stage_entity_spec.rb
+++ b/spec/serializers/stage_entity_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe StageEntity, feature_category: :continuous_integration do
+RSpec.describe StageEntity do
let(:pipeline) { create(:ci_pipeline) }
let(:request) { double('request') }
let(:user) { create(:user) }
@@ -76,8 +76,8 @@ RSpec.describe StageEntity, feature_category: :continuous_integration do
context 'with a skipped stage ' do
let(:stage) { create(:ci_stage, status: 'skipped') }
- it 'does not contain play_all_manual' do
- expect(subject[:status][:action]).not_to be_present
+ it 'contains play_all_manual' do
+ expect(subject[:status][:action]).to be_present
end
end
diff --git a/spec/support/shared_examples/ci/stage_shared_examples.rb b/spec/support/shared_examples/ci/stage_shared_examples.rb
index cdb1058e584..a2849e00d27 100644
--- a/spec/support/shared_examples/ci/stage_shared_examples.rb
+++ b/spec/support/shared_examples/ci/stage_shared_examples.rb
@@ -21,7 +21,7 @@ RSpec.shared_examples 'manual playable stage' do |stage_type|
context 'when is skipped' do
let(:status) { 'skipped' }
- it { is_expected.to be_falsy }
+ it { is_expected.to be_truthy }
end
end
end
diff --git a/spec/support/shared_examples/helpers/super_sidebar_shared_examples.rb b/spec/support/shared_examples/helpers/super_sidebar_shared_examples.rb
index 636b9870bd7..9da804b3140 100644
--- a/spec/support/shared_examples/helpers/super_sidebar_shared_examples.rb
+++ b/spec/support/shared_examples/helpers/super_sidebar_shared_examples.rb
@@ -32,4 +32,6 @@ RSpec.shared_examples 'logged-out super-sidebar context' do
it_behaves_like 'shared super sidebar context'
it { is_expected.to include({ is_logged_in: false }) }
+
+ it { expect(subject[:context_switcher_links]).to be_an(Array) }
end
diff --git a/spec/tooling/danger/stable_branch_spec.rb b/spec/tooling/danger/stable_branch_spec.rb
index 439a878a5e6..69e68f983fd 100644
--- a/spec/tooling/danger/stable_branch_spec.rb
+++ b/spec/tooling/danger/stable_branch_spec.rb
@@ -59,6 +59,8 @@ RSpec.describe Tooling::Danger::StableBranch, feature_category: :delivery do
end
context 'when not applicable' do
+ let(:current_stable_branch) { '15-1-stable-ee' }
+
where(:stable_branch?, :security_mr?) do
true | true
false | true
@@ -67,7 +69,7 @@ RSpec.describe Tooling::Danger::StableBranch, feature_category: :delivery do
with_them do
before do
- allow(fake_helper).to receive(:mr_target_branch).and_return(stable_branch? ? '15-1-stable-ee' : 'main')
+ allow(fake_helper).to receive(:mr_target_branch).and_return(stable_branch? ? current_stable_branch : 'main')
allow(fake_helper).to receive(:security_mr?).and_return(security_mr?)
end
@@ -239,7 +241,7 @@ RSpec.describe Tooling::Danger::StableBranch, feature_category: :delivery do
end
context 'when not an applicable version' do
- let(:target_branch) { '14-9-stable-ee' }
+ let(:target_branch) { '15-0-stable-ee' }
it 'warns about the package-and-test pipeline and the version' do
expect(stable_branch).to receive(:warn).with(described_class::WARN_PACKAGE_AND_TEST_MESSAGE)
@@ -297,18 +299,6 @@ RSpec.describe Tooling::Danger::StableBranch, feature_category: :delivery do
it_behaves_like 'without a failure'
end
-
- context 'when too many version API requests are made' do
- let(:parsed_response) { [{ 'version' => '15.0.0' }] }
-
- it 'adds a warning' do
- expect(HTTParty).to receive(:get).and_return(version_response).at_least(10).times
- expect(stable_branch).to receive(:warn).with(described_class::WARN_PACKAGE_AND_TEST_MESSAGE)
- expect(stable_branch).to receive(:warn).with(described_class::FAILED_VERSION_REQUEST_MESSAGE)
-
- subject
- end
- end
end
end