diff options
Diffstat (limited to 'spec')
53 files changed, 517 insertions, 416 deletions
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index 8caed2d3ac6..8bddf51a434 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -123,7 +123,7 @@ RSpec.describe Projects::ClustersController, feature_category: :deployment_manag { id: proxyable.id.to_s, namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 6b0c164e432..ef2d743c82f 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Projects::Environments::PrometheusApiController do { id: proxyable.id.to_s, namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb index c953ea02a15..7c74511e5b4 100644 --- a/spec/controllers/projects/grafana_api_controller_spec.rb +++ b/spec/controllers/projects/grafana_api_controller_spec.rb @@ -180,7 +180,7 @@ RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do embedded: true, grafana_url: 'https://grafana.example.com', namespace_id: project.namespace.full_path, - project_id: project.name + project_id: project.path } end diff --git a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb index ca95d95a730..dc59dda3322 100644 --- a/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb +++ b/spec/controllers/projects/performance_monitoring/dashboards_controller_spec.rb @@ -64,7 +64,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do post :create, params: params expect(response).to have_gitlab_http_status :created - expect(controller).to set_flash[:notice].to eq("Your dashboard has been copied. You can <a href=\"/-/ide/project/#{namespace.path}/#{project.name}/edit/#{branch_name}/-/.gitlab/dashboards/#{file_name}\">edit it here</a>.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been copied. You can <a href=\"/-/ide/project/#{project.full_path}/edit/#{branch_name}/-/.gitlab/dashboards/#{file_name}\">edit it here</a>.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'path' => ".gitlab/dashboards/#{file_name}" }) end @@ -203,7 +203,7 @@ RSpec.describe Projects::PerformanceMonitoring::DashboardsController do put :update, params: params expect(response).to have_gitlab_http_status :created - expect(controller).to set_flash[:notice].to eq("Your dashboard has been updated. You can <a href=\"/-/ide/project/#{namespace.path}/#{project.name}/edit/#{branch_name}/-/.gitlab/dashboards/#{file_name}\">edit it here</a>.") + expect(controller).to set_flash[:notice].to eq("Your dashboard has been updated. You can <a href=\"/-/ide/project/#{project.full_path}/edit/#{branch_name}/-/.gitlab/dashboards/#{file_name}\">edit it here</a>.") expect(json_response).to eq('status' => 'success', 'dashboard' => { 'default' => false, 'display_name' => "custom_dashboard.yml", 'path' => ".gitlab/dashboards/#{file_name}", 'system_dashboard' => false }) end diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index 2afd080344d..17bf9308834 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -158,9 +158,9 @@ RSpec.describe Projects::ReleasesController do it_behaves_like 'successful request' - it 'is accesible at a URL encoded path' do + it 'is accessible at a URL encoded path' do expect(edit_project_release_path(project, release)) - .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0/edit") + .to eq("/#{project.full_path}/-/releases/awesome%2Fv1.0/edit") end end @@ -199,7 +199,7 @@ RSpec.describe Projects::ReleasesController do it 'is accesible at a URL encoded path' do expect(project_release_path(project, release)) - .to eq("/#{project.namespace.path}/#{project.name}/-/releases/awesome%2Fv1.0") + .to eq("/#{project.full_path}/-/releases/awesome%2Fv1.0") end end diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 5703ab1eaff..d82f9acdd07 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -634,7 +634,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do assigned_project = page.find('[data-testid="assigned-projects"]') expect(page).to have_content('Runner assigned to project.') - expect(assigned_project).to have_content(project2.path) + expect(assigned_project).to have_content(project2.name) end end @@ -674,7 +674,7 @@ RSpec.describe "Admin Runners", feature_category: :runner_fleet do new_runner_project = page.find('[data-testid="unassigned-projects"]') expect(page).to have_content('Runner unassigned from project.') - expect(new_runner_project).to have_content(project1.path) + expect(new_runner_project).to have_content(project1.name) end end end diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb index 458f83dffb4..57a7e8ea523 100644 --- a/spec/features/explore/groups_spec.rb +++ b/spec/features/explore/groups_spec.rb @@ -29,8 +29,8 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders public and internal projects' do it do visit_page - expect(page).to have_content(public_project.name) - expect(page).to have_content(internal_project.name) + expect(page).to have_content(public_project.name).or(have_content(public_project.path)) + expect(page).to have_content(internal_project.name).or(have_content(internal_project.path)) expect(page).not_to have_content(private_project.name) end end @@ -38,7 +38,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders only public project' do it do visit_page - expect(page).to have_content(public_project.name) + expect(page).to have_content(public_project.name).or(have_content(public_project.path)) expect(page).not_to have_content(internal_project.name) expect(page).not_to have_content(private_project.name) end @@ -47,7 +47,7 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do shared_examples 'renders group in public groups area' do it do visit explore_groups_path - expect(page).to have_content(group.name) + expect(page).to have_content(group.path) end end @@ -56,32 +56,44 @@ RSpec.describe 'Explore Groups', :js, feature_category: :subgroups do sign_in(user) end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit group_path(group) } + context 'for group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit group_path(group) } + end end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit issues_group_path(group) } + context 'for issues_group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit issues_group_path(group) } + end end - it_behaves_like 'renders public and internal projects' do - subject(:visit_page) { visit merge_requests_group_path(group) } + context 'for merge_requests_group_path' do + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end end it_behaves_like 'renders group in public groups area' end context 'when signed out' do - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit group_path(group) } + context 'for group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit group_path(group) } + end end - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit issues_group_path(group) } + context 'for issues_group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit issues_group_path(group) } + end end - it_behaves_like 'renders only public project' do - subject(:visit_page) { visit merge_requests_group_path(group) } + context 'for merge_requests_group_path' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end end it_behaves_like 'renders group in public groups area' diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index bb61431d773..6443f4a6c38 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -74,7 +74,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do visit new_project_full_path expect(page).to have_current_path(new_project_full_path, ignore_query: true) - expect(find('.breadcrumbs')).to have_content(project.path) + expect(find('.breadcrumbs')).to have_content(project.name) end it 'the old project path redirects to the new path' do @@ -82,7 +82,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do visit old_project_full_path expect(page).to have_current_path(new_project_full_path, ignore_query: true) - expect(find('.breadcrumbs')).to have_content(project.path) + expect(find('.breadcrumbs')).to have_content(project.name) end end end @@ -265,7 +265,7 @@ RSpec.describe 'Edit group settings', feature_category: :subgroups do end context 'with gitlab-profile project and no README.md' do - let_it_be(:project) { create(:project, name: 'gitlab-profile', namespace: group) } + let_it_be(:project) { create(:project, path: 'gitlab-profile', namespace: group) } it 'renders Add README button and allows user to create a README via the IDE' do visit edit_group_path(group) diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb index db069b194b5..7963d4c3b22 100644 --- a/spec/features/groups/packages_spec.rb +++ b/spec/features/groups/packages_spec.rb @@ -53,7 +53,7 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do find('[data-testid="root-link"]', text: project.path).click expect(page).to have_current_path(project_path(project)) - expect(page).to have_content(project.path) + expect(page).to have_content(project.name) end context 'sorting' do diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index 8082d1bdf63..9b9c2158432 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -11,8 +11,7 @@ RSpec.describe "User browses files", :js, feature_category: :projects do "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, :repository, name: "Shop") } - let(:project2) { create(:project, :repository, name: "Another Project", path: "another-project") } + let_it_be(:project) { create(:project, :repository) } let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:user) { project.first_owner } @@ -142,7 +141,9 @@ RSpec.describe "User browses files", :js, feature_category: :projects do expect(page).to have_current_path(project_blob_path(project, "markdown/doc/raketasks/maintenance.md"), ignore_query: true) expect(page).to have_content("bundle exec rake gitlab:env:info RAILS_ENV=production") - click_link("shop") + page.within(".tree-ref-container") do + click_link(project.path) + end page.within(".tree-table") do click_link("README.md") diff --git a/spec/features/projects/settings/forked_project_settings_spec.rb b/spec/features/projects/settings/forked_project_settings_spec.rb index 28d5c080db9..6b646bcf7d3 100644 --- a/spec/features/projects/settings/forked_project_settings_spec.rb +++ b/spec/features/projects/settings/forked_project_settings_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js, feature_catego wait_for_requests - fill_in('confirm_name_input', with: forked_project.name) + fill_in('confirm_name_input', with: forked_project.path) click_button('Confirm') wait_for_requests diff --git a/spec/features/projects/settings/user_renames_a_project_spec.rb b/spec/features/projects/settings/user_renames_a_project_spec.rb index 85d50083c33..a6b72e7a297 100644 --- a/spec/features/projects/settings/user_renames_a_project_spec.rb +++ b/spec/features/projects/settings/user_renames_a_project_spec.rb @@ -37,7 +37,7 @@ RSpec.describe 'Projects > Settings > User renames a project', feature_category: it 'shows errors for invalid project path' do change_path(project, 'foo&bar') - expect(page).to have_field 'Path', with: 'gitlab' + expect(page).to have_field 'Path', with: project.path expect(page).to have_content "Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-', end in '.git' or end in '.atom'" end end diff --git a/spec/frontend/authentication/webauthn/authenticate_spec.js b/spec/frontend/authentication/webauthn/authenticate_spec.js index b1f4e43e56d..b3a634fb072 100644 --- a/spec/frontend/authentication/webauthn/authenticate_spec.js +++ b/spec/frontend/authentication/webauthn/authenticate_spec.js @@ -1,5 +1,6 @@ import $ from 'jquery'; -import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; +import htmlWebauthnAuthenticate from 'test_fixtures/webauthn/authenticate.html'; +import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import waitForPromises from 'helpers/wait_for_promises'; import WebAuthnAuthenticate from '~/authentication/webauthn/authenticate'; import MockWebAuthnDevice from './mock_webauthn_device'; @@ -35,7 +36,7 @@ describe('WebAuthnAuthenticate', () => { }; beforeEach(() => { - loadHTMLFixture('webauthn/authenticate.html'); + setHTMLFixture(htmlWebauthnAuthenticate); fallbackElement = document.createElement('div'); fallbackElement.classList.add('js-2fa-form'); webAuthnDevice = new MockWebAuthnDevice(); diff --git a/spec/frontend/authentication/webauthn/register_spec.js b/spec/frontend/authentication/webauthn/register_spec.js index 773481346fc..5f0691782a7 100644 --- a/spec/frontend/authentication/webauthn/register_spec.js +++ b/spec/frontend/authentication/webauthn/register_spec.js @@ -1,5 +1,6 @@ import $ from 'jquery'; -import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; +import htmlWebauthnRegister from 'test_fixtures/webauthn/register.html'; +import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import { trimText } from 'helpers/text_helper'; import setWindowLocation from 'helpers/set_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; @@ -25,7 +26,7 @@ describe('WebAuthnRegister', () => { let component; beforeEach(() => { - loadHTMLFixture('webauthn/register.html'); + setHTMLFixture(htmlWebauthnRegister); webAuthnDevice = new MockWebAuthnDevice(); container = $('#js-register-token-2fa'); component = new WebAuthnRegister(container, { diff --git a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js index 7940518f1e8..1fa613d15d4 100644 --- a/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js +++ b/spec/frontend/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view_spec.js @@ -5,27 +5,31 @@ import { GlSearchBoxByType, GlLink, } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; -import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes'; +import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; import DropdownContentsLabelsView from '~/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view.vue'; import LabelItem from '~/sidebar/components/labels/labels_select_vue/label_item.vue'; - +import { stubComponent } from 'helpers/stub_component'; import * as actions from '~/sidebar/components/labels/labels_select_vue/store/actions'; import * as getters from '~/sidebar/components/labels/labels_select_vue/store/getters'; import mutations from '~/sidebar/components/labels/labels_select_vue/store/mutations'; import defaultState from '~/sidebar/components/labels/labels_select_vue/store/state'; -import { mockConfig, mockLabels, mockRegularLabel } from './mock_data'; +import { mockConfig, mockLabels } from './mock_data'; Vue.use(Vuex); describe('DropdownContentsLabelsView', () => { let wrapper; + let store; + + const focusInputMock = jest.fn(); + const updateSelectedLabelsMock = jest.fn(); + const toggleDropdownContentsMock = jest.fn(); - const createComponent = (initialState = mockConfig) => { - const store = new Vuex.Store({ + const createComponent = (initialState = mockConfig, mountFn = shallowMountExtended) => { + store = new Vuex.Store({ getters, mutations, state: { @@ -36,14 +40,20 @@ describe('DropdownContentsLabelsView', () => { actions: { ...actions, fetchLabels: jest.fn(), + updateSelectedLabels: updateSelectedLabelsMock, + toggleDropdownContents: toggleDropdownContentsMock, }, }); store.dispatch('setInitialState', initialState); - store.dispatch('receiveLabelsSuccess', mockLabels); - wrapper = shallowMount(DropdownContentsLabelsView, { + wrapper = mountFn(DropdownContentsLabelsView, { store, + stubs: { + GlSearchBoxByType: stubComponent(GlSearchBoxByType, { + methods: { focusInput: focusInputMock }, + }), + }, }); }; @@ -51,44 +61,54 @@ describe('DropdownContentsLabelsView', () => { createComponent(); }); - const findDropdownContent = () => wrapper.find('[data-testid="dropdown-content"]'); - const findDropdownTitle = () => wrapper.find('[data-testid="dropdown-title"]'); - const findDropdownFooter = () => wrapper.find('[data-testid="dropdown-footer"]'); + const findDropdownContent = () => wrapper.findByTestId('dropdown-content'); + const findDropdownTitle = () => wrapper.findByTestId('dropdown-title'); + const findDropdownFooter = () => wrapper.findByTestId('dropdown-footer'); + const findNoMatchingResults = () => wrapper.findByTestId('no-matching-results'); + const findCreateLabelLink = () => wrapper.findByTestId('create-label-link'); + const findLabelsList = () => wrapper.findByTestId('labels-list'); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType); + const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver); + const findLabelItems = () => wrapper.findAllComponents(LabelItem); + + const setCurrentHighlightItem = (value) => { + let initialValue = -1; + + while (initialValue < value) { + findLabelsList().trigger('keydown.down'); + initialValue += 1; + } + }; describe('computed', () => { describe('visibleLabels', () => { - it('returns matching labels filtered with `searchKey`', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchKey: 'bug', - }); - - expect(wrapper.vm.visibleLabels.length).toBe(1); - expect(wrapper.vm.visibleLabels[0].title).toBe('Bug'); + beforeEach(() => { + createComponent(undefined, mountExtended); + store.dispatch('receiveLabelsSuccess', mockLabels); }); - it('returns matching labels with fuzzy filtering', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchKey: 'bg', - }); + it('returns matching labels filtered with `searchKey`', async () => { + await findSearchBoxByType().vm.$emit('input', 'bug'); - expect(wrapper.vm.visibleLabels.length).toBe(2); - expect(wrapper.vm.visibleLabels[0].title).toBe('Bug'); - expect(wrapper.vm.visibleLabels[1].title).toBe('Boog'); + const labelItems = findLabelItems(); + expect(labelItems).toHaveLength(1); + expect(labelItems.at(0).text()).toBe('Bug'); }); - it('returns all labels when `searchKey` is empty', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchKey: '', - }); + it('returns matching labels with fuzzy filtering', async () => { + await findSearchBoxByType().vm.$emit('input', 'bg'); - expect(wrapper.vm.visibleLabels.length).toBe(mockLabels.length); + const labelItems = findLabelItems(); + expect(labelItems).toHaveLength(2); + expect(labelItems.at(0).text()).toBe('Bug'); + expect(labelItems.at(1).text()).toBe('Boog'); + }); + + it('returns all labels when `searchKey` is empty', async () => { + await findSearchBoxByType().vm.$emit('input', ''); + + expect(findLabelItems()).toHaveLength(mockLabels.length); }); }); @@ -102,17 +122,11 @@ describe('DropdownContentsLabelsView', () => { `( 'returns $returnValue when searchKey is "$searchKey" and visibleLabels is $labelsDescription', async ({ searchKey, labels, returnValue }) => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchKey, - }); - - wrapper.vm.$store.dispatch('receiveLabelsSuccess', labels); + store.dispatch('receiveLabelsSuccess', labels); - await nextTick(); + await findSearchBoxByType().vm.$emit('input', searchKey); - expect(wrapper.vm.showNoMatchingResultsMessage).toBe(returnValue); + expect(findNoMatchingResults().isVisible()).toBe(returnValue); }, ); }); @@ -121,171 +135,134 @@ describe('DropdownContentsLabelsView', () => { describe('methods', () => { const fakePreventDefault = jest.fn(); - describe('isLabelSelected', () => { - it('returns true when provided `label` param is one of the selected labels', () => { - expect(wrapper.vm.isLabelSelected(mockRegularLabel)).toBe(true); - }); - - it('returns false when provided `label` param is not one of the selected labels', () => { - expect(wrapper.vm.isLabelSelected(mockLabels[1])).toBe(false); - }); - }); - describe('handleComponentAppear', () => { it('calls `focusInput` on searchInput field', async () => { - wrapper.vm.$refs.searchInput.focusInput = jest.fn(); + findIntersectionObserver().vm.$emit('appear'); - await wrapper.vm.handleComponentAppear(); + await nextTick(); - expect(wrapper.vm.$refs.searchInput.focusInput).toHaveBeenCalled(); + expect(focusInputMock).toHaveBeenCalled(); }); }); describe('handleComponentDisappear', () => { - it('calls action `receiveLabelsSuccess` with empty array', () => { - jest.spyOn(wrapper.vm, 'receiveLabelsSuccess'); + it('calls action `receiveLabelsSuccess` with empty array', async () => { + jest.spyOn(store, 'dispatch'); - wrapper.vm.handleComponentDisappear(); + await findIntersectionObserver().vm.$emit('disappear'); - expect(wrapper.vm.receiveLabelsSuccess).toHaveBeenCalledWith([]); + expect(store.dispatch).toHaveBeenCalledWith(expect.anything(), []); }); }); describe('handleCreateLabelClick', () => { - it('calls actions `receiveLabelsSuccess` with empty array and `toggleDropdownContentsCreateView`', () => { - jest.spyOn(wrapper.vm, 'receiveLabelsSuccess'); - jest.spyOn(wrapper.vm, 'toggleDropdownContentsCreateView'); + it('calls actions `receiveLabelsSuccess` with empty array and `toggleDropdownContentsCreateView`', async () => { + jest.spyOn(store, 'dispatch'); - wrapper.vm.handleCreateLabelClick(); + await findCreateLabelLink().vm.$emit('click'); - expect(wrapper.vm.receiveLabelsSuccess).toHaveBeenCalledWith([]); - expect(wrapper.vm.toggleDropdownContentsCreateView).toHaveBeenCalled(); + expect(store.dispatch).toHaveBeenCalledWith('receiveLabelsSuccess', []); + expect(store.dispatch).toHaveBeenCalledWith('toggleDropdownContentsCreateView'); }); }); describe('handleKeyDown', () => { - it('decreases `currentHighlightItem` value by 1 when Up arrow key is pressed', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 1, - }); - - wrapper.vm.handleKeyDown({ - keyCode: UP_KEY_CODE, - }); - - expect(wrapper.vm.currentHighlightItem).toBe(0); + beforeEach(() => { + createComponent(undefined, mountExtended); + store.dispatch('receiveLabelsSuccess', mockLabels); }); - it('increases `currentHighlightItem` value by 1 when Down arrow key is pressed', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 1, - }); + it('decreases `currentHighlightItem` value by 1 when Up arrow key is pressed', async () => { + await setCurrentHighlightItem(1); + + expect(findLabelItems().at(1).classes()).toContain('is-focused'); - wrapper.vm.handleKeyDown({ - keyCode: DOWN_KEY_CODE, - }); + await findLabelsList().trigger('keydown.up'); - expect(wrapper.vm.currentHighlightItem).toBe(2); + expect(findLabelItems().at(1).classes()).not.toContain('is-focused'); }); - it('resets the search text when the Enter key is pressed', () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 1, - searchKey: 'bug', - }); + it('increases `currentHighlightItem` value by 1 when Down arrow key is pressed', async () => { + expect(findLabelItems().at(0).classes()).not.toContain('is-focused'); - wrapper.vm.handleKeyDown({ - keyCode: ENTER_KEY_CODE, - preventDefault: fakePreventDefault, - }); + await findLabelsList().trigger('keydown.down'); - expect(wrapper.vm.searchKey).toBe(''); - expect(fakePreventDefault).toHaveBeenCalled(); + expect(findLabelItems().at(0).classes()).toContain('is-focused'); }); - it('calls action `updateSelectedLabels` with currently highlighted label when Enter key is pressed', () => { - jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 2, - }); - - wrapper.vm.handleKeyDown({ - keyCode: ENTER_KEY_CODE, - preventDefault: fakePreventDefault, - }); + it('resets the search text when the Enter key is pressed', async () => { + await setCurrentHighlightItem(1); + await findSearchBoxByType().vm.$emit('input', 'bug'); + await findLabelsList().trigger('keydown.enter', { preventDefault: fakePreventDefault }); - expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([mockLabels[2]]); + expect(findSearchBoxByType().props('value')).toBe(''); + expect(fakePreventDefault).toHaveBeenCalled(); }); - it('calls action `toggleDropdownContents` when Esc key is pressed', () => { - jest.spyOn(wrapper.vm, 'toggleDropdownContents').mockImplementation(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 1, - }); + it('calls action `updateSelectedLabels` with currently highlighted label when Enter key is pressed', async () => { + await setCurrentHighlightItem(2); + await findLabelsList().trigger('keydown.enter', { preventDefault: fakePreventDefault }); + + expect(updateSelectedLabelsMock).toHaveBeenCalledWith(expect.anything(), [mockLabels[2]]); + }); - wrapper.vm.handleKeyDown({ - keyCode: ESC_KEY_CODE, - }); + it('calls action `toggleDropdownContents` when Esc key is pressed', async () => { + await setCurrentHighlightItem(1); + await findLabelsList().trigger('keydown.esc'); - expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled(); + expect(toggleDropdownContentsMock).toHaveBeenCalled(); }); - it('calls action `scrollIntoViewIfNeeded` in next tick when any key is pressed', async () => { - jest.spyOn(wrapper.vm, 'scrollIntoViewIfNeeded').mockImplementation(); - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 1, - }); + it('calls action `scrollIntoViewIfNeeded` in next tick when esc key is pressed', async () => { + const containerTop = 500; + const labelTop = 0; - wrapper.vm.handleKeyDown({ - keyCode: DOWN_KEY_CODE, - }); + jest + .spyOn(findDropdownContent().element, 'getBoundingClientRect') + .mockReturnValueOnce({ top: containerTop }); - await nextTick(); - expect(wrapper.vm.scrollIntoViewIfNeeded).toHaveBeenCalled(); + await setCurrentHighlightItem(1); + await findLabelsList().trigger('keydown.esc'); + + expect(findDropdownContent().element.scrollTop).toBe(labelTop - containerTop); }); }); describe('handleLabelClick', () => { beforeEach(() => { - jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation(); + createComponent(undefined, mountExtended); + store.dispatch('receiveLabelsSuccess', mockLabels); }); it('calls action `updateSelectedLabels` with provided `label` param', () => { - wrapper.vm.handleLabelClick(mockRegularLabel); + findLabelItems().at(0).findComponent(GlLink).vm.$emit('click'); - expect(wrapper.vm.updateSelectedLabels).toHaveBeenCalledWith([mockRegularLabel]); + expect(updateSelectedLabelsMock).toHaveBeenCalledWith(expect.anything(), [ + { ...mockLabels[0], indeterminate: expect.anything(), set: expect.anything() }, + ]); }); it('calls action `toggleDropdownContents` when `state.allowMultiselect` is false', () => { - jest.spyOn(wrapper.vm, 'toggleDropdownContents'); - wrapper.vm.$store.state.allowMultiselect = false; + store.state.allowMultiselect = false; - wrapper.vm.handleLabelClick(mockRegularLabel); + findLabelItems().at(0).findComponent(GlLink).vm.$emit('click'); - expect(wrapper.vm.toggleDropdownContents).toHaveBeenCalled(); + expect(toggleDropdownContentsMock).toHaveBeenCalled(); }); }); }); describe('template', () => { + beforeEach(() => { + store.dispatch('receiveLabelsSuccess', mockLabels); + }); + it('renders gl-intersection-observer as component root', () => { expect(wrapper.findComponent(GlIntersectionObserver).exists()).toBe(true); }); it('renders gl-loading-icon component when `labelsFetchInProgress` prop is true', async () => { - wrapper.vm.$store.dispatch('requestLabels'); + store.dispatch('requestLabels'); await nextTick(); const loadingIconEl = findLoadingIcon(); @@ -325,30 +302,19 @@ describe('DropdownContentsLabelsView', () => { }); it('renders label elements for all labels', () => { - expect(wrapper.findAllComponents(LabelItem)).toHaveLength(mockLabels.length); + expect(findLabelItems()).toHaveLength(mockLabels.length); }); it('renders label element with `highlight` set to true when value of `currentHighlightItem` is more than -1', async () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - currentHighlightItem: 0, - }); + await setCurrentHighlightItem(0); - await nextTick(); const labelItemEl = findDropdownContent().findComponent(LabelItem); expect(labelItemEl.attributes('highlight')).toBe('true'); }); it('renders element containing "No matching results" when `searchKey` does not match with any label', async () => { - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ - searchKey: 'abc', - }); - - await nextTick(); + await findSearchBoxByType().vm.$emit('input', 'abc'); const noMatchEl = findDropdownContent().find('li'); expect(noMatchEl.isVisible()).toBe(true); @@ -356,7 +322,7 @@ describe('DropdownContentsLabelsView', () => { }); it('renders empty content while loading', async () => { - wrapper.vm.$store.state.labelsFetchInProgress = true; + store.state.labelsFetchInProgress = true; await nextTick(); const dropdownContent = findDropdownContent(); @@ -380,7 +346,7 @@ describe('DropdownContentsLabelsView', () => { }); it('does not render "Create label" footer link when `state.allowLabelCreate` is `false`', async () => { - wrapper.vm.$store.state.allowLabelCreate = false; + store.state.allowLabelCreate = false; await nextTick(); const createLabelLink = findDropdownFooter().findAllComponents(GlLink).at(0); diff --git a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb index 44147987ebb..0485796fe56 100644 --- a/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb +++ b/spec/graphql/mutations/ci/job_token_scope/add_project_spec.rb @@ -20,6 +20,10 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :cont mutation.resolve(**mutation_args) end + before do + stub_feature_flags(frozen_outbound_job_token_scopes_override: false) + end + context 'when user is not logged in' do let(:current_user) { nil } @@ -43,10 +47,10 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :cont target_project.add_guest(current_user) end - it 'adds target project to the outbound job token scope by default' do + it 'adds target project to the inbound job token scope by default' do expect do expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) - end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + end.to change { Ci::JobToken::ProjectScopeLink.inbound.count }.by(1) end context 'when mutation uses the direction argument' do @@ -55,10 +59,8 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :cont context 'when targeting the outbound allowlist' do let(:direction) { :outbound } - it 'adds the target project' do - expect do - expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) - end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + it 'raises an error' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ArgumentError) end end @@ -73,6 +75,42 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :cont end end + context 'when FF frozen_outbound_job_token_scopes is disabled' do + before do + stub_feature_flags(frozen_outbound_job_token_scopes: false) + end + + it 'adds target project to the outbound job token scope by default' do + expect do + expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) + end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + end + + context 'when mutation uses the direction argument' do + let(:mutation_args) { super().merge!(direction: direction) } + + context 'when targeting the outbound allowlist' do + let(:direction) { :outbound } + + it 'adds the target project' do + expect do + expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) + end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + end + end + + context 'when targeting the inbound allowlist' do + let(:direction) { :inbound } + + it 'adds the target project' do + expect do + expect(subject).to include(ci_job_token_scope: be_present, errors: be_empty) + end.to change { Ci::JobToken::ProjectScopeLink.inbound.count }.by(1) + end + end + end + end + context 'when the service returns an error' do let(:service) { double(:service) } @@ -81,7 +119,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddProject, feature_category: :cont project, current_user ).and_return(service) - expect(service).to receive(:execute).with(target_project, direction: :outbound).and_return(ServiceResponse.error(message: 'The error message')) + expect(service).to receive(:execute).with(target_project, direction: :inbound).and_return(ServiceResponse.error(message: 'The error message')) expect(subject.fetch(:ci_job_token_scope)).to be_nil expect(subject.fetch(:errors)).to include("The error message") diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index ae84331dcdb..ce2c6d0477b 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -451,7 +451,7 @@ RSpec.describe ApplicationHelper do find_file: nil, group: nil, project_id: project.id, - project: project.name, + project: project.path, namespace_id: project.namespace.id } ) @@ -469,7 +469,7 @@ RSpec.describe ApplicationHelper do find_file: nil, group: project.group.name, project_id: project.id, - project: project.name, + project: project.path, namespace_id: project.namespace.id } ) @@ -495,7 +495,7 @@ RSpec.describe ApplicationHelper do find_file: nil, group: nil, project_id: issue.project.id, - project: issue.project.name, + project: issue.project.path, namespace_id: issue.project.namespace.id } ) diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index e8e981251e3..600131270c6 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -62,19 +62,19 @@ RSpec.describe LabelsHelper do end context 'with a project as subject' do - let(:namespace) { build(:namespace, name: 'foo3') } - let(:subject) { build(:project, namespace: namespace, name: 'bar3') } + let(:namespace) { build(:namespace) } + let(:subject) { build(:project, namespace: namespace) } it 'links to project issues page' do - expect(link_to_label(label_presenter)).to match %r{<a.*href="/foo3/bar3/-/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m + expect(link_to_label(label_presenter)).to match %r{<a.*href="/#{subject.full_path}/-/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end context 'with a group as subject' do - let(:subject) { build(:group, name: 'bar') } + let(:subject) { build(:group) } it 'links to group issues page' do - expect(link_to_label(label_presenter)).to match %r{<a.*href="/groups/bar/-/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m + expect(link_to_label(label_presenter)).to match %r{<a.*href="/groups/#{subject.path}/-/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 9b01622bd17..a0bd8df81cc 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -38,30 +38,6 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do subject { diffs_tab_pane_data(project, merge_request, {}) } context 'for endpoint_diff_for_path' do - context 'when default project namespace' do - let_it_be(:project) { create(:project) } - let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - - it 'returns expected values' do - expect( - subject[:endpoint_diff_for_path] - ).to eq("/#{project.full_path}/-/merge_requests/#{merge_request.iid}/diff_for_path.json") - end - end - - context 'when group project namespace' do - let_it_be(:group) { create(:group, :public) } - let_it_be(:project) { create(:project, :private, group: group) } - let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - - it 'returns expected values' do - namespace = "#{group.name}/#{project.name}" - expect( - subject[:endpoint_diff_for_path] - ).to include("/#{namespace}/-/merge_requests/#{merge_request.iid}/diff_for_path.json") - end - end - context 'when sub-group project namespace' do let_it_be(:group) { create(:group, :public) } let_it_be(:subgroup) { create(:group, :private, parent: group) } @@ -69,32 +45,21 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } it 'returns expected values' do - namespace = "#{group.name}/#{subgroup.name}/#{project.name}" - expect( - subject[:endpoint_diff_for_path] - ).to include("#{namespace}/-/merge_requests/#{merge_request.iid}/diff_for_path.json") - end - end - - context 'when sub-sub-group project namespace' do - let_it_be(:group) { create(:group, :public) } - let_it_be(:subgroup) { create(:group, :private, parent: group) } - let_it_be(:subsubgroup) { create(:group, :private, parent: subgroup) } - let_it_be(:project) { create(:project, :private, group: subsubgroup) } - let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - - it 'returns expected values' do - namespace = "#{group.name}/#{subgroup.name}/#{subsubgroup.name}/#{project.name}" expect( subject[:endpoint_diff_for_path] - ).to include("#{namespace}/-/merge_requests/#{merge_request.iid}/diff_for_path.json") + ).to include("#{project.full_path}/-/merge_requests/#{merge_request.iid}/diff_for_path.json") end end end end describe '#merge_path_description' do - let_it_be(:project) { create(:project) } + # Using let_it_be(:project) raises the following error, so we use need to use let(:project): + # ActiveRecord::InvalidForeignKey: + # PG::ForeignKeyViolation: ERROR: insert or update on table "fork_network_members" violates foreign key + # constraint "fk_rails_a40860a1ca" + # DETAIL: Key (fork_network_id)=(8) is not present in table "fork_networks". + let(:project) { create(:project) } let(:forked_project) { fork_project(project) } let(:merge_request_forked) { create(:merge_request, source_project: forked_project, target_project: project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } diff --git a/spec/lib/api/entities/project_job_token_scope_spec.rb b/spec/lib/api/entities/project_job_token_scope_spec.rb new file mode 100644 index 00000000000..cceef9e7f30 --- /dev/null +++ b/spec/lib/api/entities/project_job_token_scope_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::API::Entities::ProjectJobTokenScope, feature_category: :secrets_management do + let_it_be(:project) do + create(:project, + :public, + ci_inbound_job_token_scope_enabled: true, + ci_outbound_job_token_scope_enabled: true + ) + end + + let_it_be(:current_user) { create(:user) } + + let(:options) { { current_user: current_user } } + let(:entity) { described_class.new(project, options) } + + describe "#as_json" do + subject { entity.as_json } + + it 'includes basic fields' do + expect(subject).to eq( + inbound_enabled: true, + outbound_enabled: true + ) + end + + it 'includes basic fields' do + project.update!(ci_inbound_job_token_scope_enabled: false) + + expect(subject).to eq( + inbound_enabled: false, + outbound_enabled: true + ) + end + end +end diff --git a/spec/lib/container_registry/path_spec.rb b/spec/lib/container_registry/path_spec.rb index aa6876225b5..c9fa3ec690b 100644 --- a/spec/lib/container_registry/path_spec.rb +++ b/spec/lib/container_registry/path_spec.rb @@ -143,8 +143,8 @@ RSpec.describe ContainerRegistry::Path do let(:path) { 'some_group/some_project' } before do - create(:project, group: group, name: 'some_project') - create(:project, name: 'some_project') + create(:project, group: group, path: 'some_project') + create(:project, path: 'some_project') end it 'returns a correct project' do @@ -162,7 +162,7 @@ RSpec.describe ContainerRegistry::Path do context 'when matching multi-level path' do let(:project) do - create(:project, group: group, name: 'some_project') + create(:project, group: group, path: 'some_project') end context 'when using the zero-level path' do @@ -212,7 +212,7 @@ RSpec.describe ContainerRegistry::Path do let(:group) { create(:group, path: 'Some_Group') } before do - create(:project, group: group, name: 'some_project') + create(:project, group: group, path: 'some_project') end context 'when project path equal repository path' do @@ -255,7 +255,7 @@ RSpec.describe ContainerRegistry::Path do let(:group) { create(:group, path: 'SomeGroup') } before do - create(:project, group: group, name: 'MyProject') + create(:project, group: group, path: 'MyProject') end it 'returns downcased project path' do diff --git a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb index ef5049158c1..fa675950fc1 100644 --- a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb +++ b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb @@ -380,55 +380,5 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category: end end end - - context 'when FF ci_fix_max_includes is disabled' do - before do - stub_feature_flags(ci_fix_max_includes: false) - end - - context 'when total file count exceeds max_includes' do - context 'when files are nested' do - let(:files) do - [ - Gitlab::Ci::Config::External::File::Local.new({ local: 'nested_configs.yml' }, context) - ] - end - - it 'raises Processor::IncludeError' do - allow(context).to receive(:max_includes).and_return(1) - expect { process }.to raise_error(Gitlab::Ci::Config::External::Processor::IncludeError) - end - end - - context 'when files are not nested' do - let(:files) do - [ - Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context), - Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file2.yml' }, context) - ] - end - - it 'raises Mapper::TooManyIncludesError' do - allow(context).to receive(:max_includes).and_return(1) - expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError) - end - end - - context 'when files are duplicates' do - let(:files) do - [ - Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context), - Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context), - Gitlab::Ci::Config::External::File::Local.new({ local: 'myfolder/file1.yml' }, context) - ] - end - - it 'raises error' do - allow(context).to receive(:max_includes).and_return(2) - expect { process }.to raise_error(Gitlab::Ci::Config::External::Mapper::TooManyIncludesError) - end - end - end - end end end diff --git a/spec/lib/gitlab/consul/internal_spec.rb b/spec/lib/gitlab/consul/internal_spec.rb index 28dcaac9ff2..ff76269fe76 100644 --- a/spec/lib/gitlab/consul/internal_spec.rb +++ b/spec/lib/gitlab/consul/internal_spec.rb @@ -77,9 +77,11 @@ RSpec.describe Gitlab::Consul::Internal do shared_examples 'returns nil given blank value of' do |input_symbol| [nil, ''].each do |value| - let(input_symbol) { value } + context "with #{value}" do + let(input_symbol) { value } - it { is_expected.to be_nil } + it { is_expected.to be_nil } + end end end diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb index f13d98ec9b9..bb68bca5dfa 100644 --- a/spec/lib/gitlab/email/message/repository_push_spec.rb +++ b/spec/lib/gitlab/email/message/repository_push_spec.rb @@ -45,7 +45,7 @@ RSpec.describe Gitlab::Email::Message::RepositoryPush do describe '#project_name_with_namespace' do subject { message.project_name_with_namespace } - it { is_expected.to eq "#{group.name} / #{project.path}" } + it { is_expected.to eq "#{group.name} / #{project.name}" } end describe '#author' do diff --git a/spec/lib/gitlab/import_export/project/export_task_spec.rb b/spec/lib/gitlab/import_export/project/export_task_spec.rb index 3dd1e9257cc..95971d08175 100644 --- a/spec/lib/gitlab/import_export/project/export_task_spec.rb +++ b/spec/lib/gitlab/import_export/project/export_task_spec.rb @@ -10,14 +10,14 @@ RSpec.describe Gitlab::ImportExport::Project::ExportTask, :silence_stdout do let(:measurement_enabled) { false } let(:file_path) { 'spec/fixtures/gitlab/import_export/test_project_export.tar.gz' } let(:project) { create(:project, creator: user, namespace: user.namespace) } - let(:project_name) { project.name } + let(:project_path) { project.path } let(:rake_task) { described_class.new(task_params) } let(:task_params) do { username: username, namespace_path: namespace_path, - project_path: project_name, + project_path: project_path, file_path: file_path, measurement_enabled: measurement_enabled } @@ -48,10 +48,10 @@ RSpec.describe Gitlab::ImportExport::Project::ExportTask, :silence_stdout do end context 'when project is not found' do - let(:project_name) { 'invalid project name' } + let(:project_path) { 'invalid project path' } it 'logs an error' do - expect { subject }.to output(/Project with path: #{project_name} was not found. Please provide correct project path/).to_stdout + expect { subject }.to output(/Project with path: #{project_path} was not found. Please provide correct project path/).to_stdout end it 'returns false' do diff --git a/spec/lib/gitlab/redis/cluster_rate_limiting_spec.rb b/spec/lib/gitlab/redis/cluster_rate_limiting_spec.rb deleted file mode 100644 index 3eba3233f08..00000000000 --- a/spec/lib/gitlab/redis/cluster_rate_limiting_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Redis::ClusterRateLimiting, feature_category: :redis do - include_examples "redis_new_instance_shared_examples", 'cluster_rate_limiting', Gitlab::Redis::Cache -end diff --git a/spec/mailers/emails/pages_domains_spec.rb b/spec/mailers/emails/pages_domains_spec.rb index cf17f2e5ebf..ff446b83412 100644 --- a/spec/mailers/emails/pages_domains_spec.rb +++ b/spec/mailers/emails/pages_domains_spec.rb @@ -58,7 +58,7 @@ RSpec.describe Emails::PagesDomains do end describe '#pages_domain_enabled_email' do - let(:email_subject) { "#{project.path} | GitLab Pages domain '#{domain.domain}' has been enabled" } + let(:email_subject) { "#{project.name} | GitLab Pages domain '#{domain.domain}' has been enabled" } let(:link_anchor) { 'steps' } subject { Notify.pages_domain_enabled_email(domain, user) } @@ -69,7 +69,7 @@ RSpec.describe Emails::PagesDomains do end describe '#pages_domain_disabled_email' do - let(:email_subject) { "#{project.path} | GitLab Pages domain '#{domain.domain}' has been disabled" } + let(:email_subject) { "#{project.name} | GitLab Pages domain '#{domain.domain}' has been disabled" } let(:link_anchor) { '4-verify-the-domains-ownership' } subject { Notify.pages_domain_disabled_email(domain, user) } @@ -82,7 +82,7 @@ RSpec.describe Emails::PagesDomains do end describe '#pages_domain_verification_succeeded_email' do - let(:email_subject) { "#{project.path} | Verification succeeded for GitLab Pages domain '#{domain.domain}'" } + let(:email_subject) { "#{project.name} | Verification succeeded for GitLab Pages domain '#{domain.domain}'" } let(:link_anchor) { 'steps' } subject { Notify.pages_domain_verification_succeeded_email(domain, user) } @@ -93,7 +93,7 @@ RSpec.describe Emails::PagesDomains do end describe '#pages_domain_verification_failed_email' do - let(:email_subject) { "#{project.path} | ACTION REQUIRED: Verification failed for GitLab Pages domain '#{domain.domain}'" } + let(:email_subject) { "#{project.name} | ACTION REQUIRED: Verification failed for GitLab Pages domain '#{domain.domain}'" } let(:link_anchor) { 'steps' } subject { Notify.pages_domain_verification_failed_email(domain, user) } @@ -104,7 +104,7 @@ RSpec.describe Emails::PagesDomains do end describe '#pages_domain_auto_ssl_failed_email' do - let(:email_subject) { "#{project.path} | ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '#{domain.domain}'" } + let(:email_subject) { "#{project.name} | ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '#{domain.domain}'" } subject { Notify.pages_domain_auto_ssl_failed_email(domain, user) } diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb index cb122fa09fc..52bb23588e3 100644 --- a/spec/models/design_management/design_spec.rb +++ b/spec/models/design_management/design_spec.rb @@ -514,9 +514,9 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do describe '#to_reference' do let(:filename) { 'homescreen.jpg' } - let(:namespace) { build(:namespace, id: non_existing_record_id, path: 'sample-namespace') } - let(:project) { build(:project, name: 'sample-project', namespace: namespace) } - let(:group) { build(:group, name: 'Group', path: 'sample-group') } + let(:namespace) { build(:namespace, id: non_existing_record_id) } + let(:project) { build(:project, namespace: namespace) } + let(:group) { build(:group) } let(:issue) { build(:issue, iid: 1, project: project) } let(:design) { build(:design, filename: filename, issue: issue, project: project) } @@ -536,7 +536,7 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do design.to_reference(group, full: true) ] - expect(refs).to all(eq 'sample-namespace/sample-project#1/designs[homescreen.jpg]') + expect(refs).to all(eq "#{project.full_path}#1/designs[homescreen.jpg]") end end @@ -547,7 +547,7 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do design.to_reference(group, full: false) ] - expect(refs).to all(eq 'sample-namespace/sample-project#1[homescreen.jpg]') + expect(refs).to all(eq "#{project.full_path}#1[homescreen.jpg]") end end @@ -596,7 +596,7 @@ RSpec.describe DesignManagement::Design, feature_category: :design_management do 'url_filename' => filename, 'issue' => issue.iid.to_s, 'namespace' => design.project.namespace.to_param, - 'project' => design.project.name + 'project' => design.project.to_param ) end diff --git a/spec/models/integrations/chat_message/deployment_message_spec.rb b/spec/models/integrations/chat_message/deployment_message_spec.rb index 8da27ef5aa0..d16c191bd08 100644 --- a/spec/models/integrations/chat_message/deployment_message_spec.rb +++ b/spec/models/integrations/chat_message/deployment_message_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Integrations::ChatMessage::DeploymentMessage do let_it_be(:user) { create(:user, name: 'John Smith', username: 'smith') } let_it_be(:namespace) { create(:namespace, name: 'myspace') } - let_it_be(:project) { create(:project, :repository, namespace: namespace, name: 'myproject') } + let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'myproject') } let_it_be(:commit) { project.commit('HEAD') } let_it_be(:ci_build) { create(:ci_build, project: project) } let_it_be(:environment) { create(:environment, name: 'myenvironment', project: project) } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 38f50f7627e..cf48a602104 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -590,8 +590,8 @@ RSpec.describe Issue, feature_category: :team_planning do end describe '#to_reference' do - let_it_be(:namespace) { create(:namespace, path: 'sample-namespace') } - let_it_be(:project) { create(:project, name: 'sample-project', namespace: namespace) } + let_it_be(:namespace) { create(:namespace) } + let_it_be(:project) { create(:project, namespace: namespace) } let_it_be(:issue) { create(:issue, project: project) } context 'when nil argument' do @@ -617,17 +617,17 @@ RSpec.describe Issue, feature_category: :team_planning do context 'when cross-project in same namespace' do let(:another_project) do - create(:project, name: 'another-project', namespace: project.namespace) + create(:project, namespace: project.namespace) end it 'returns a cross-project reference' do - expect(issue.to_reference(another_project)).to eq "sample-project##{issue.iid}" + expect(issue.to_reference(another_project)).to eq "#{project.path}##{issue.iid}" end end context 'when cross-project in different namespace' do let(:another_namespace) { build(:namespace, id: non_existing_record_id, path: 'another-namespace') } - let(:another_namespace_project) { build(:project, path: 'another-project', namespace: another_namespace) } + let(:another_namespace_project) { build(:project, namespace: another_namespace) } it 'returns complete path to the issue' do expect(issue.to_reference(another_namespace_project)).to eq "#{project.full_path}##{issue.iid}" @@ -638,7 +638,7 @@ RSpec.describe Issue, feature_category: :team_planning do context 'when argument is a namespace' do context 'when same as issue' do it 'returns path to the issue with the project name' do - expect(issue.to_reference(namespace)).to eq "sample-project##{issue.iid}" + expect(issue.to_reference(namespace)).to eq "#{project.path}##{issue.iid}" end it 'returns full reference with full: true' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index a66302da6f5..6cd4b9e0753 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1049,7 +1049,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev end describe '#to_reference' do - let(:project) { build(:project, name: 'sample-project') } + let(:project) { build(:project) } let(:merge_request) { build(:merge_request, target_project: project, iid: 1) } it 'returns a String reference to the object' do @@ -1057,12 +1057,12 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) - expect(merge_request.to_reference(another_project)).to eq "sample-project!1" + another_project = build(:project, namespace: project.namespace) + expect(merge_request.to_reference(another_project)).to eq "#{project.path}!1" end it 'returns a String reference with the full path' do - expect(merge_request.to_reference(full: true)).to eq(project.full_path + '!1') + expect(merge_request.to_reference(full: true)).to eq("#{project.full_path}!1") end end diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 9f6b1f8016b..8bd7c057a6e 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -439,8 +439,8 @@ RSpec.describe Milestone do describe '#to_reference' do let(:group) { build_stubbed(:group) } - let(:project) { build_stubbed(:project, name: 'sample-project') } - let(:another_project) { build_stubbed(:project, name: 'another-project', namespace: project.namespace) } + let(:project) { build_stubbed(:project, path: 'sample-project') } + let(:another_project) { build_stubbed(:project, path: 'another-project', namespace: project.namespace) } context 'for a project milestone' do let(:milestone) { build_stubbed(:milestone, iid: 1, project: project, name: 'milestone') } diff --git a/spec/models/operations/feature_flag_spec.rb b/spec/models/operations/feature_flag_spec.rb index dd1ff95a16d..4a39c5dc234 100644 --- a/spec/models/operations/feature_flag_spec.rb +++ b/spec/models/operations/feature_flag_spec.rb @@ -37,8 +37,8 @@ RSpec.describe Operations::FeatureFlag do end describe '#to_reference' do - let(:namespace) { build(:namespace, path: 'sample-namespace') } - let(:project) { build(:project, name: 'sample-project', namespace: namespace) } + let(:namespace) { build(:namespace) } + let(:project) { build(:project, namespace: namespace) } let(:feature_flag) { build(:operations_feature_flag, iid: 1, project: project) } it 'returns feature flag id' do @@ -46,7 +46,7 @@ RSpec.describe Operations::FeatureFlag do end it 'returns complete path to the feature flag with full: true' do - expect(feature_flag.to_reference(full: true)).to eq '[feature_flag:sample-namespace/sample-project/1]' + expect(feature_flag.to_reference(full: true)).to eq "[feature_flag:#{project.full_path}/1]" end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 00a94c80198..92849efc462 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -788,7 +788,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do let(:new_project) do build(:project, - name: project_pending_deletion.name, + path: project_pending_deletion.path, namespace: project_pending_deletion.namespace) end @@ -1692,7 +1692,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do context 'with namespace' do before do @group = create(:group, name: 'gitlab') - @project = create(:project, name: 'gitlabhq', namespace: @group) + @project = create(:project, path: 'gitlabhq', namespace: @group) end it { expect(@project.to_param).to eq('gitlabhq') } @@ -7995,7 +7995,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do describe '#activity_path' do it 'returns the project activity_path' do - expected_path = "/#{project.namespace.path}/#{project.name}/activity" + expected_path = "/#{project.full_path}/activity" expect(project.activity_path).to eq(expected_path) end diff --git a/spec/models/service_desk_setting_spec.rb b/spec/models/service_desk_setting_spec.rb index dba33e829c6..b9679b82bd0 100644 --- a/spec/models/service_desk_setting_spec.rb +++ b/spec/models/service_desk_setting_spec.rb @@ -82,8 +82,8 @@ RSpec.describe ServiceDeskSetting, feature_category: :service_desk do # group1/test/one and group1/test-one will both have 'group-test-one' slug let_it_be(:group) { create(:group) } let_it_be(:subgroup) { create(:group, parent: group, name: 'test') } - let_it_be(:project1) { create(:project, name: 'test-one', group: group) } - let_it_be(:project2) { create(:project, name: 'one', group: subgroup) } + let_it_be(:project1) { create(:project, path: 'test-one', group: group) } + let_it_be(:project2) { create(:project, path: 'one', group: subgroup) } let_it_be(:project_key) { 'key' } let!(:setting) do create(:service_desk_setting, project: project1, project_key: project_key) diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index da1f2653676..495c409f7b5 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -145,7 +145,7 @@ RSpec.describe Snippet do describe '#to_reference' do context 'when snippet belongs to a project' do - let(:project) { build(:project, name: 'sample-project') } + let(:project) { build(:project) } let(:snippet) { build(:snippet, id: 1, project: project) } it 'returns a String reference to the object' do @@ -153,8 +153,8 @@ RSpec.describe Snippet do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) - expect(snippet.to_reference(another_project)).to eq "sample-project$1" + another_project = build(:project, namespace: project.namespace) + expect(snippet.to_reference(another_project)).to eq "#{project.path}$1" end end @@ -166,7 +166,7 @@ RSpec.describe Snippet do end it 'still returns shortest reference when project arg present' do - another_project = build(:project, name: 'another-project') + another_project = build(:project) expect(snippet.to_reference(another_project)).to eq "$1" end end diff --git a/spec/presenters/project_hook_presenter_spec.rb b/spec/presenters/project_hook_presenter_spec.rb index a85865652d8..7c02548af08 100644 --- a/spec/presenters/project_hook_presenter_spec.rb +++ b/spec/presenters/project_hook_presenter_spec.rb @@ -11,7 +11,7 @@ RSpec.describe ProjectHookPresenter do subject { web_hook.present.logs_details_path(web_hook_log) } let(:expected_path) do - "/#{project.namespace.path}/#{project.name}/-/hooks/#{web_hook.id}/hook_logs/#{web_hook_log.id}" + "/#{project.full_path}/-/hooks/#{web_hook.id}/hook_logs/#{web_hook_log.id}" end it { is_expected.to eq(expected_path) } @@ -21,7 +21,7 @@ RSpec.describe ProjectHookPresenter do subject { web_hook.present.logs_retry_path(web_hook_log) } let(:expected_path) do - "/#{project.namespace.path}/#{project.name}/-/hooks/#{web_hook.id}/hook_logs/#{web_hook_log.id}/retry" + "/#{project.full_path}/-/hooks/#{web_hook.id}/hook_logs/#{web_hook_log.id}/retry" end it { is_expected.to eq(expected_path) } diff --git a/spec/presenters/service_hook_presenter_spec.rb b/spec/presenters/service_hook_presenter_spec.rb index c7703593327..48c3f6f0a22 100644 --- a/spec/presenters/service_hook_presenter_spec.rb +++ b/spec/presenters/service_hook_presenter_spec.rb @@ -12,7 +12,7 @@ RSpec.describe ServiceHookPresenter do subject { service_hook.present.logs_details_path(web_hook_log) } let(:expected_path) do - "/#{project.namespace.path}/#{project.name}/-/settings/integrations/#{integration.to_param}/hook_logs/#{web_hook_log.id}" + "/#{project.full_path}/-/settings/integrations/#{integration.to_param}/hook_logs/#{web_hook_log.id}" end it { is_expected.to eq(expected_path) } @@ -22,7 +22,7 @@ RSpec.describe ServiceHookPresenter do subject { service_hook.present.logs_retry_path(web_hook_log) } let(:expected_path) do - "/#{project.namespace.path}/#{project.name}/-/settings/integrations/#{integration.to_param}/hook_logs/#{web_hook_log.id}/retry" + "/#{project.full_path}/-/settings/integrations/#{integration.to_param}/hook_logs/#{web_hook_log.id}/retry" end it { is_expected.to eq(expected_path) } diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb index 55e728b2141..8791d793cb4 100644 --- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb @@ -53,14 +53,29 @@ RSpec.describe 'CiJobTokenScopeAddProject', feature_category: :continuous_integr before do target_project.add_developer(current_user) + stub_feature_flags(frozen_outbound_job_token_scopes_override: false) end - it 'adds the target project to the job token scope' do + it 'adds the target project to the inbound job token scope' do expect do post_graphql_mutation(mutation, current_user: current_user) expect(response).to have_gitlab_http_status(:success) expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty - end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + end.to change { Ci::JobToken::ProjectScopeLink.inbound.count }.by(1) + end + + context 'when FF frozen_outbound_job_token_scopes is disabled' do + before do + stub_feature_flags(frozen_outbound_job_token_scopes: false) + end + + it 'adds the target project to the outbound job token scope' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty + end.to change { Ci::JobToken::ProjectScopeLink.outbound.count }.by(1) + end end context 'when invalid target project is provided' do diff --git a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb index 0951d165d46..79e86c1f2af 100644 --- a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb @@ -5,6 +5,10 @@ require 'spec_helper' RSpec.describe 'ProjectCiCdSettingsUpdate', feature_category: :continuous_integration do include GraphqlHelpers + before do + stub_feature_flags(frozen_outbound_job_token_scopes_override: false) + end + let_it_be(:project) do create(:project, keep_latest_artifact: true, @@ -61,7 +65,7 @@ RSpec.describe 'ProjectCiCdSettingsUpdate', feature_category: :continuous_integr expect(project.keep_latest_artifact).to eq(false) end - it 'updates job_token_scope_enabled' do + it 'allows setting job_token_scope_enabled to false' do post_graphql_mutation(mutation, current_user: user) project.reload @@ -70,6 +74,51 @@ RSpec.describe 'ProjectCiCdSettingsUpdate', feature_category: :continuous_integr expect(project.ci_outbound_job_token_scope_enabled).to eq(false) end + context 'when job_token_scope_enabled: true' do + let(:variables) do + { + full_path: project.full_path, + keep_latest_artifact: false, + job_token_scope_enabled: true, + inbound_job_token_scope_enabled: false, + opt_in_jwt: true + } + end + + it 'prevents the update', :aggregate_failures do + project.update!(ci_outbound_job_token_scope_enabled: false) + post_graphql_mutation(mutation, current_user: user) + + project.reload + + expect(response).to have_gitlab_http_status(:success) + expect(graphql_errors).to( + include( + hash_including( + 'message' => 'job_token_scope_enabled can only be set to false' + ) + ) + ) + expect(project.ci_outbound_job_token_scope_enabled).to eq(false) + end + end + + context 'when FF frozen_outbound_job_token_scopes is disabled' do + before do + stub_feature_flags(frozen_outbound_job_token_scopes: false) + end + + it 'allows setting job_token_scope_enabled to true' do + project.update!(ci_outbound_job_token_scope_enabled: true) + post_graphql_mutation(mutation, current_user: user) + + project.reload + + expect(response).to have_gitlab_http_status(:success) + expect(project.ci_outbound_job_token_scope_enabled).to eq(false) + end + end + it 'does not update job_token_scope_enabled if not specified' do variables.except!(:job_token_scope_enabled) diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb index a816b3870a1..1006319eabf 100644 --- a/spec/requests/api/internal/pages_spec.rb +++ b/spec/requests/api/internal/pages_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe API::Internal::Pages, feature_category: :pages do - let_it_be(:group) { create(:group, name: 'mygroup') } - let_it_be_with_reload(:project) { create(:project, name: 'myproject', group: group) } + let_it_be(:group) { create(:group) } + let_it_be_with_reload(:project) { create(:project, group: group) } let(:auth_header) do { @@ -228,7 +228,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do end it 'responds with 204 No Content' do - get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') @@ -243,7 +243,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do context 'with a regular project' do it 'responds with the correct domain configuration' do - get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') @@ -255,7 +255,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do 'project_id' => project.id, 'access_control' => false, 'https_only' => false, - 'prefix' => '/myproject/', + 'prefix' => "/#{project.path}/", 'source' => { 'type' => 'zip', 'path' => deployment.file.url(expire_at: 1.day.from_now), @@ -274,7 +274,7 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do it 'avoids N+1 queries' do control = ActiveRecord::QueryRecorder.new do - get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } end 3.times do @@ -282,17 +282,17 @@ RSpec.describe API::Internal::Pages, feature_category: :pages do project.mark_pages_as_deployed end - expect { get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } } + expect { get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } } .not_to exceed_query_limit(control) end context 'with a group root project' do before do - project.update!(path: 'mygroup.gitlab-pages.io') + project.update!(path: "#{group.path}.gitlab-pages.io") end it 'responds with the correct domain configuration' do - get api('/internal/pages'), headers: auth_header, params: { host: 'mygroup.gitlab-pages.io' } + get api('/internal/pages'), headers: auth_header, params: { host: "#{group.path}.gitlab-pages.io" } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') diff --git a/spec/requests/api/project_job_token_scope_spec.rb b/spec/requests/api/project_job_token_scope_spec.rb new file mode 100644 index 00000000000..df210a00012 --- /dev/null +++ b/spec/requests/api/project_job_token_scope_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::ProjectJobTokenScope, feature_category: :secrets_management do + describe 'GET /projects/:id/job_token_scope' do + let_it_be(:project) { create(:project, :public) } + let_it_be(:user) { create(:user) } + + let(:get_job_token_scope_path) { "/projects/#{project.id}/job_token_scope" } + + subject { get api(get_job_token_scope_path, user) } + + context 'when unauthenticated user (missing user)' do + context 'for public project' do + it 'does not return ci cd settings of job token' do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + + get api(get_job_token_scope_path) + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + end + + context 'when authenticated user as maintainer' do + before_all { project.add_maintainer(user) } + + it 'returns ci cd settings for job token scope' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to include( + "inbound_enabled" => true, + "outbound_enabled" => false + ) + end + + it 'returns the correct ci cd settings for job token scope after change' do + project.update!(ci_inbound_job_token_scope_enabled: false) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to include( + "inbound_enabled" => false, + "outbound_enabled" => false + ) + end + + it 'returns unauthorized and blank response when invalid auth credentials are given' do + invalid_personal_access_token = build(:personal_access_token, user: user) + + get api(get_job_token_scope_path, user, personal_access_token: invalid_personal_access_token) + + expect(response).to have_gitlab_http_status(:unauthorized) + expect(json_response).not_to include("inbound_enabled", "outbound_enabled") + end + end + + context 'when authenticated user as developer' do + before do + project.add_developer(user) + end + + it 'returns forbidden and no ci cd settings for public project' do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + + subject + + expect(response).to have_gitlab_http_status(:forbidden) + expect(json_response).not_to include("inbound_enabled", "outbound_enabled") + end + end + end +end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 49bfdf053ef..a47052f2d0a 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -63,8 +63,6 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d create(:project, :private, :repository, - name: 'second_project', - path: 'second_project', creator_id: user.id, namespace: user.namespace, merge_requests_enabled: false, @@ -82,8 +80,6 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d let_it_be(:project4, reload: true) do create(:project, - name: 'third_project', - path: 'third_project', creator_id: user4.id, namespace: user4.namespace) end @@ -190,7 +186,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d context 'when unauthenticated' do it_behaves_like 'projects response' do - let(:filter) { { search: project.name } } + let(:filter) { { search: project.path } } let(:current_user) { user } let(:projects) { [project] } end @@ -545,7 +541,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d context 'and using search' do it_behaves_like 'projects response' do - let(:filter) { { search: project.name } } + let(:filter) { { search: project.path } } let(:current_user) { user } let(:projects) { [project] } end @@ -966,7 +962,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d expect(json_response.length).to eq(1) project_names = json_response.map { |proj| proj['name'] } - expect(project_names).to contain_exactly('Test Public Project') + expect(project_names).to contain_exactly(project_4.name) end end end @@ -1470,11 +1466,11 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d end it 'creates a new project initialized with a README.md' do - project = attributes_for(:project, initialize_with_readme: 1, name: 'somewhere') + project = attributes_for(:project, initialize_with_readme: 1) post api(path, user), params: project - expect(json_response['readme_url']).to eql("#{Gitlab.config.gitlab.url}/#{json_response['namespace']['full_path']}/somewhere/-/blob/master/README.md") + expect(json_response['readme_url']).to eql("#{Gitlab.config.gitlab.url}/#{json_response['namespace']['full_path']}/#{json_response['path']}/-/blob/master/README.md") end it 'sets tag list to a project (deprecated)' do @@ -1660,7 +1656,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d end describe 'GET /users/:user_id/projects/' do - let!(:public_project) { create(:project, :public, name: 'public_project', creator_id: user4.id, namespace: user4.namespace) } + let_it_be(:public_project) { create(:project, :public, creator_id: user4.id, namespace: user4.namespace) } it 'returns error when user not found' do get api("/users/#{non_existing_record_id}/projects/") @@ -1697,7 +1693,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d end context 'and using id_after' do - let!(:another_public_project) { create(:project, :public, name: 'another_public_project', creator_id: user4.id, namespace: user4.namespace) } + let_it_be(:another_public_project) { create(:project, :public, creator_id: user4.id, namespace: user4.namespace) } it 'only returns projects with id_after filter given' do get api("/users/#{user4.id}/projects?id_after=#{public_project.id}", user) @@ -1719,7 +1715,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d end context 'and using id_before' do - let!(:another_public_project) { create(:project, :public, name: 'another_public_project', creator_id: user4.id, namespace: user4.namespace) } + let_it_be(:another_public_project) { create(:project, :public, creator_id: user4.id, namespace: user4.namespace) } it 'only returns projects with id_before filter given' do get api("/users/#{user4.id}/projects?id_before=#{another_public_project.id}", user) @@ -1741,7 +1737,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :projects d end context 'and using both id_before and id_after' do - let!(:more_projects) { create_list(:project, 5, :public, creator_id: user4.id, namespace: user4.namespace) } + let_it_be(:more_projects) { create_list(:project, 5, :public, creator_id: user4.id, namespace: user4.namespace) } it 'only returns projects with id matching the range' do get api("/users/#{user4.id}/projects?id_after=#{more_projects.first.id}&id_before=#{more_projects.last.id}", user) diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb index 4b388304621..b8c10de2302 100644 --- a/spec/requests/api/release/links_spec.rb +++ b/spec/requests/api/release/links_spec.rb @@ -174,7 +174,7 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do specify do get api("/projects/#{project.id}/releases/v0.1/assets/links/#{link.id}", maintainer) - expect(json_response['direct_asset_url']).to eq("http://localhost/#{project.namespace.path}/#{project.name}/-/releases/#{release.tag}/downloads/bin/bigfile.exe") + expect(json_response['direct_asset_url']).to eq("http://localhost/#{project.full_path}/-/releases/#{release.tag}/downloads/bin/bigfile.exe") end end @@ -391,7 +391,7 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do put api("/projects/#{project.id}/releases/v0.1/assets/links/#{release_link.id}", maintainer), params: params.merge(direct_asset_path: '/binaries/awesome-app.msi') - expect(json_response['direct_asset_url']).to eq("http://localhost/#{project.namespace.path}/#{project.name}/-/releases/#{release.tag}/downloads/binaries/awesome-app.msi") + expect(json_response['direct_asset_url']).to eq("http://localhost/#{project.full_path}/-/releases/#{release.tag}/downloads/binaries/awesome-app.msi") end end diff --git a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb index dc87cc872e3..e6bdb2a3fc6 100644 --- a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb +++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb @@ -4,10 +4,10 @@ require 'spec_helper' RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness, feature_category: :continuous_integration do - let_it_be(:group) { create(:group, name: 'my-organization') } + let_it_be(:group) { create(:group) } - let(:upstream_project) { create(:project, :repository, name: 'upstream', group: group) } - let(:downstream_project) { create(:project, :repository, name: 'downstream', group: group) } + let(:upstream_project) { create(:project, :repository, group: group) } + let(:downstream_project) { create(:project, :repository, group: group) } let(:user) { create(:user) } let(:service) do @@ -28,7 +28,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl stage: test resource_group: iOS trigger: - project: my-organization/downstream + project: #{downstream_project.full_path} strategy: depend YAML end diff --git a/spec/services/ci/job_token_scope/add_project_service_spec.rb b/spec/services/ci/job_token_scope/add_project_service_spec.rb index e6674ee384f..dc7ad81afef 100644 --- a/spec/services/ci/job_token_scope/add_project_service_spec.rb +++ b/spec/services/ci/job_token_scope/add_project_service_spec.rb @@ -37,8 +37,8 @@ RSpec.describe Ci::JobTokenScope::AddProjectService, feature_category: :continuo it_behaves_like 'adds project' - it 'creates an outbound link by default' do - expect(resulting_direction).to eq('outbound') + it 'creates an inbound link by default' do + expect(resulting_direction).to eq('inbound') end context 'when direction is specified' do diff --git a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb index 7e61d690ddd..48941792c4b 100644 --- a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb +++ b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute', let(:project) { cluster.project } let(:environment) { create(:environment, project: project) } let(:cluster_project) { cluster.cluster_project } - let(:namespace) { "#{project.name}-#{project.id}-#{environment.slug}" } + let(:namespace) { "#{project.path}-#{project.id}-#{environment.slug}" } subject do described_class.new( diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb index 10399bed655..27da948079e 100644 --- a/spec/services/groups/transfer_service_spec.rb +++ b/spec/services/groups/transfer_service_spec.rb @@ -458,7 +458,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline, feature_category: :subg it 'updates projects path' do new_parent_path = new_parent_group.path group.projects.each do |project| - expect(project.full_path).to eq("#{new_parent_path}/#{group.path}/#{project.name}") + expect(project.full_path).to eq("#{new_parent_path}/#{group.path}/#{project.path}") end end @@ -525,7 +525,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline, feature_category: :subg it 'updates projects path' do new_parent_path = new_parent_group.path group.projects.each do |project| - expect(project.full_path).to eq("#{new_parent_path}/#{group.path}/#{project.name}") + expect(project.full_path).to eq("#{new_parent_path}/#{group.path}/#{project.path}") end end @@ -576,7 +576,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline, feature_category: :subg it 'updates projects path' do new_parent_path = "#{new_parent_group.path}/#{group.path}" subgroup1.projects.each do |project| - project_full_path = "#{new_parent_path}/#{project.namespace.path}/#{project.name}" + project_full_path = "#{new_parent_path}/#{project.namespace.path}/#{project.path}" expect(project.full_path).to eq(project_full_path) end end diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 2aba2303dd1..4ba72b5870d 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -150,12 +150,11 @@ RSpec.describe Projects::ForkService, feature_category: :source_code_management context 'project already exists' do it "fails due to validation, not transaction failure" do - @existing_project = create(:project, :repository, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace) + @existing_project = create(:project, :repository, creator_id: @to_user.id, path: @from_project.path, namespace: @to_namespace) @to_project = fork_project(@from_project, @to_user, namespace: @to_namespace, using_service: true) expect(@existing_project).to be_persisted expect(@to_project).not_to be_persisted - expect(@to_project.errors[:name]).to eq(['has already been taken']) expect(@to_project.errors[:path]).to eq(['has already been taken']) end end @@ -301,10 +300,9 @@ RSpec.describe Projects::ForkService, feature_category: :source_code_management context 'project already exists in group' do it 'fails due to validation, not transaction failure' do - existing_project = create(:project, :repository, name: @project.name, namespace: @group) + existing_project = create(:project, :repository, path: @project.path, namespace: @group) to_project = fork_project(@project, @group_owner, @opts) expect(existing_project.persisted?).to be_truthy - expect(to_project.errors[:name]).to eq(['has already been taken']) expect(to_project.errors[:path]).to eq(['has already been taken']) end end diff --git a/spec/support/shared_contexts/glfm/example_snapshot_fixtures.rb b/spec/support/shared_contexts/glfm/example_snapshot_fixtures.rb index 22b401bc841..83bf622af67 100644 --- a/spec/support/shared_contexts/glfm/example_snapshot_fixtures.rb +++ b/spec/support/shared_contexts/glfm/example_snapshot_fixtures.rb @@ -8,7 +8,7 @@ RSpec.shared_context 'with GLFM example snapshot fixtures' do # NOTE: We hardcode the IDs on all fixtures to prevent variability in the # rendered HTML/Prosemirror JSON, and to minimize the need for normalization: # https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#normalization - create(:project, :repository, creator: user, group: group, name: 'glfm_project', id: 77777) + create(:project, :repository, creator: user, group: group, path: 'glfm_project', id: 77777) end let_it_be(:project_snippet) { create(:project_snippet, title: 'glfm_project_snippet', id: 88888, project: project) } diff --git a/spec/support/shared_examples/mailers/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb index 4d039eccbf7..cf1ab7697ab 100644 --- a/spec/support/shared_examples/mailers/notify_shared_examples.rb +++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb @@ -59,7 +59,7 @@ end RSpec.shared_examples 'an email with X-GitLab headers containing project details' do it 'has X-GitLab-Project headers' do aggregate_failures do - full_path_as_domain = "#{project.name}.#{project.namespace.path}" + full_path_as_domain = "#{project.path}.#{project.namespace.path}" is_expected.to have_header('X-GitLab-Project', /#{project.name}/) is_expected.to have_header('X-GitLab-Project-Id', /#{project.id}/) is_expected.to have_header('X-GitLab-Project-Path', /#{project.full_path}/) diff --git a/spec/support/shared_examples/requests/user_activity_shared_examples.rb b/spec/support/shared_examples/requests/user_activity_shared_examples.rb index 37da1ce5c63..9c0165f7150 100644 --- a/spec/support/shared_examples/requests/user_activity_shared_examples.rb +++ b/spec/support/shared_examples/requests/user_activity_shared_examples.rb @@ -5,7 +5,7 @@ RSpec.shared_examples 'updating of user activity' do |paths_to_visit| before do group = create(:group, name: 'group') - project = create(:project, :public, namespace: group, name: 'project') + project = create(:project, :public, namespace: group, path: 'project') create(:issue, project: project, iid: 10) create(:merge_request, source_project: project, iid: 15) diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index 76519545e24..3340725dd6d 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe FileUploader do - let(:group) { create(:group, name: 'awesome') } - let(:project) { create(:project, :legacy_storage, namespace: group, name: 'project') } + let(:group) { create(:group, path: 'awesome') } + let(:project) { create(:project, :legacy_storage, namespace: group, path: 'project') } let(:uploader) { described_class.new(project, :avatar) } let(:upload) { double(model: project, path: "#{secret}/foo.jpg") } let(:secret) { "55dc16aa0edd05693fd98b5051e83321" } # this would be nicer as SecureRandom.hex, but the shared_examples breaks @@ -23,7 +23,7 @@ RSpec.describe FileUploader do context 'uses hashed storage' do context 'when rolled out attachments' do - let(:project) { build_stubbed(:project, namespace: group, name: 'project') } + let(:project) { build_stubbed(:project, namespace: group, path: 'project') } include_examples 'builds correct paths', store_dir: %r{@hashed/\h{2}/\h{2}/\h+}, @@ -31,7 +31,7 @@ RSpec.describe FileUploader do end context 'when only repositories are rolled out' do - let(:project) { build_stubbed(:project, namespace: group, name: 'project', storage_version: Project::HASHED_STORAGE_FEATURES[:repository]) } + let(:project) { build_stubbed(:project, namespace: group, path: 'project', storage_version: Project::HASHED_STORAGE_FEATURES[:repository]) } it_behaves_like 'builds correct legacy storage paths' end |