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-07-05 18:10:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-05 18:10:10 +0300
commitc4acd4624d61ef923453561a698c905c0ffa7b57 (patch)
tree8248d88e7c9957e20f1aaa95d814d13f4d1e65ce /spec
parent1c359370b3970c41dd8aa0c69fe177f39cb58298 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/grafana_api_controller_spec.rb268
-rw-r--r--spec/features/abuse_report_spec.rb5
-rw-r--r--spec/features/users/rss_spec.rb8
-rw-r--r--spec/features/users/show_spec.rb28
-rw-r--r--spec/frontend/lib/utils/forms_spec.js111
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js26
-rw-r--r--spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js43
-rw-r--r--spec/frontend/users/profile/actions/components/user_actions_app_spec.js38
-rw-r--r--spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb56
-rw-r--r--spec/graphql/types/environment_type_spec.rb2
-rw-r--r--spec/graphql/types/metrics/dashboard_type_spec.rb22
-rw-r--r--spec/helpers/issuables_helper_spec.rb6
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb2
-rw-r--r--spec/lib/gitlab/manifest_import/metadata_spec.rb89
-rw-r--r--spec/lib/gitlab/pagination/keyset/iterator_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb8
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb32
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb8
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb4
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb4
-rw-r--r--spec/models/concerns/milestoneish_spec.rb16
-rw-r--r--spec/models/integration_spec.rb12
-rw-r--r--spec/models/protected_branch/push_access_level_spec.rb77
-rw-r--r--spec/models/protected_tag/create_access_level_spec.rb130
-rw-r--r--spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb104
-rw-r--r--spec/requests/api/graphql/metrics/dashboard_query_spec.rb114
-rw-r--r--spec/services/system_notes/time_tracking_service_spec.rb12
-rw-r--r--spec/services/work_items/export_csv_service_spec.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb30
-rw-r--r--spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb132
-rw-r--r--spec/views/profiles/show.html.haml_spec.rb2
-rw-r--r--spec/workers/integrations/execute_worker_spec.rb14
34 files changed, 563 insertions, 848 deletions
diff --git a/spec/controllers/projects/grafana_api_controller_spec.rb b/spec/controllers/projects/grafana_api_controller_spec.rb
deleted file mode 100644
index 9bc4a83030e..00000000000
--- a/spec/controllers/projects/grafana_api_controller_spec.rb
+++ /dev/null
@@ -1,268 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::GrafanaApiController, feature_category: :metrics do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:reporter) { create(:user) }
- let_it_be(:guest) { create(:user) }
- let(:anonymous) { nil }
- let(:user) { reporter }
-
- before_all do
- project.add_reporter(reporter)
- project.add_guest(guest)
- end
-
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- sign_in(user) if user
- end
-
- describe 'GET #proxy' do
- let(:proxy_service) { instance_double(Grafana::ProxyService) }
- let(:params) do
- {
- namespace_id: project.namespace.full_path,
- project_id: project.path,
- proxy_path: 'api/v1/query_range',
- datasource_id: '1',
- query: 'rate(relevant_metric)',
- start_time: '1570441248',
- end_time: '1570444848',
- step: '900'
- }
- end
-
- before do
- allow(Grafana::ProxyService).to receive(:new).and_return(proxy_service)
- allow(proxy_service).to receive(:execute).and_return(service_result)
- end
-
- shared_examples_for 'error response' do |http_status|
- it "returns #{http_status}" do
- get :proxy, params: params
-
- expect(response).to have_gitlab_http_status(http_status)
- expect(json_response['status']).to eq('error')
- expect(json_response['message']).to eq('error message')
- end
- end
-
- shared_examples_for 'accessible' do
- let(:service_result) { nil }
-
- it 'returns non erroneous response' do
- get :proxy, params: params
-
- # We don't care about the specific code as long it's not an error.
- expect(response).to have_gitlab_http_status(:no_content)
- end
- end
-
- shared_examples_for 'not accessible' do
- let(:service_result) { nil }
-
- it 'returns 404 Not found' do
- get :proxy, params: params
-
- expect(response).to have_gitlab_http_status(:not_found)
- expect(Grafana::ProxyService).not_to have_received(:new)
- end
- end
-
- shared_examples_for 'login required' do
- let(:service_result) { nil }
-
- it 'redirects to login page' do
- get :proxy, params: params
-
- expect(response).to redirect_to(new_user_session_path)
- expect(Grafana::ProxyService).not_to have_received(:new)
- end
- end
-
- context 'with a successful result' do
- let(:service_result) { { status: :success, body: '{}' } }
-
- it 'returns a grafana datasource response' do
- get :proxy, params: params
-
- expect(Grafana::ProxyService).to have_received(:new).with(
- project, '1', 'api/v1/query_range',
- {
- 'query' => params[:query],
- 'start' => params[:start_time],
- 'end' => params[:end_time],
- 'step' => params[:step]
- }
- )
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to eq({})
- end
- end
-
- context 'when the request is still unavailable' do
- let(:service_result) { nil }
-
- it 'returns 204 no content' do
- get :proxy, params: params
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(json_response['status']).to eq('processing')
- expect(json_response['message']).to eq('Not ready yet. Try again later.')
- end
- end
-
- context 'when an error has occurred' do
- context 'with an error accessing grafana' do
- let(:service_result) do
- {
- http_status: :service_unavailable,
- status: :error,
- message: 'error message'
- }
- end
-
- it_behaves_like 'error response', :service_unavailable
- end
-
- context 'with a processing error' do
- let(:service_result) do
- {
- status: :error,
- message: 'error message'
- }
- end
-
- it_behaves_like 'error response', :bad_request
- end
- end
-
- context 'as guest' do
- let(:user) { guest }
-
- it_behaves_like 'not accessible'
- end
-
- context 'as anonymous' do
- let(:user) { anonymous }
-
- it_behaves_like 'not accessible'
- end
-
- context 'on a private project' do
- let_it_be(:project) { create(:project, :private) }
-
- before_all do
- project.add_guest(guest)
- end
-
- context 'as anonymous' do
- let(:user) { anonymous }
-
- it_behaves_like 'login required'
- end
-
- context 'as guest' do
- let(:user) { guest }
-
- it_behaves_like 'accessible'
- end
- end
-
- context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
- it_behaves_like 'not accessible'
- end
- end
-
- describe 'GET #metrics_dashboard' do
- let(:service_result) { { status: :success, dashboard: '{}' } }
- let(:params) do
- {
- format: :json,
- embedded: true,
- grafana_url: 'https://grafana.example.com',
- namespace_id: project.namespace.full_path,
- project_id: project.path
- }
- end
-
- before do
- allow(Gitlab::Metrics::Dashboard::Finder)
- .to receive(:find)
- .and_return(service_result)
- end
-
- context 'when the result is still processing' do
- let(:service_result) { nil }
-
- it 'returns 204 no content' do
- get :metrics_dashboard, params: params
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
- end
-
- context 'when the result was successful' do
- it 'returns the dashboard response' do
- get :metrics_dashboard, params: params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to include({
- 'dashboard' => '{}',
- 'status' => 'success'
- })
- expect(json_response).to include('metrics_data')
- end
- end
-
- context 'when an error has occurred' do
- shared_examples_for 'error response' do |http_status|
- it "returns #{http_status}" do
- get :metrics_dashboard, params: params
-
- expect(response).to have_gitlab_http_status(http_status)
- expect(json_response['status']).to eq('error')
- expect(json_response['message']).to eq('error message')
- end
- end
-
- context 'with an error accessing grafana' do
- let(:service_result) do
- {
- http_status: :service_unavailable,
- status: :error,
- message: 'error message'
- }
- end
-
- it_behaves_like 'error response', :service_unavailable
- end
-
- context 'with a processing error' do
- let(:service_result) { { status: :error, message: 'error message' } }
-
- it_behaves_like 'error response', :bad_request
- end
-
- context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
- it 'returns 404 Not found' do
- get :metrics_dashboard, params: params
-
- expect(response).to have_gitlab_http_status(:not_found)
- expect(response.body).to be_empty
- end
- end
- end
- end
-end
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index 82b7379b67c..ae3859280b1 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
before do
sign_in(reporter1)
stub_feature_flags(moved_mr_sidebar: false)
+ stub_feature_flags(user_profile_overflow_menu_vue: false)
end
describe 'report abuse to administrator' do
@@ -122,6 +123,10 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
end
end
+ # TODO: implement tests before the FF "user_profile_overflow_menu_vue" is turned on
+ # See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122971
+ # Related Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/416983
+
private
def fill_and_submit_abuse_category_form(category = "They're posting spam.")
diff --git a/spec/features/users/rss_spec.rb b/spec/features/users/rss_spec.rb
index bc37c9941ce..39b6d049e43 100644
--- a/spec/features/users/rss_spec.rb
+++ b/spec/features/users/rss_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe 'User RSS', feature_category: :user_profile do
let(:user) { create(:user) }
let(:path) { user_path(create(:user)) }
+ before do
+ stub_feature_flags(user_profile_overflow_menu_vue: false)
+ end
+
context 'when signed in' do
before do
sign_in(user)
@@ -22,4 +26,8 @@ RSpec.describe 'User RSS', feature_category: :user_profile do
it_behaves_like "it has an RSS button without a feed token"
end
+
+ # TODO: implement tests before the FF "user_profile_overflow_menu_vue" is turned on
+ # See: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122971
+ # Related Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/416974
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index 9c4a1b36ecc..f8653b22377 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -9,10 +9,32 @@ RSpec.describe 'User page', feature_category: :user_profile do
subject(:visit_profile) { visit(user_path(user)) }
- it 'shows user id' do
- subject
+ context 'with "user_profile_overflow_menu_vue" feature flag enabled', :js do
+ it 'does not show the user id in the profile info' do
+ subject
+
+ expect(page).not_to have_content("User ID: #{user.id}")
+ end
+
+ it 'shows copy user id action in the dropdown' do
+ subject
+
+ find('[data-testid="base-dropdown-toggle"').click
+
+ expect(page).to have_content("Copy user ID: #{user.id}")
+ end
+ end
+
+ context 'with "user_profile_overflow_menu_vue" feature flag disabled', :js do
+ before do
+ stub_feature_flags(user_profile_overflow_menu_vue: false)
+ end
+
+ it 'shows user id' do
+ subject
- expect(page).to have_content("User ID: #{user.id}")
+ expect(page).to have_content("User ID: #{user.id}")
+ end
end
it 'shows name on breadcrumbs' do
diff --git a/spec/frontend/lib/utils/forms_spec.js b/spec/frontend/lib/utils/forms_spec.js
index 2f71b26b29a..b97f5bf3c51 100644
--- a/spec/frontend/lib/utils/forms_spec.js
+++ b/spec/frontend/lib/utils/forms_spec.js
@@ -1,7 +1,12 @@
import {
serializeForm,
serializeFormObject,
+ safeTrim,
isEmptyValue,
+ hasMinimumLength,
+ isParseableAsInteger,
+ isIntegerGreaterThan,
+ isEmail,
parseRailsFormFields,
} from '~/lib/utils/forms';
@@ -99,6 +104,22 @@ describe('lib/utils/forms', () => {
});
});
+ describe('safeTrim', () => {
+ it.each`
+ input | returnValue
+ ${''} | ${''}
+ ${[]} | ${[]}
+ ${null} | ${null}
+ ${undefined} | ${undefined}
+ ${' '} | ${''}
+ ${'hello '} | ${'hello'}
+ ${'hello'} | ${'hello'}
+ ${0} | ${0}
+ `('returns $returnValue for value $input', ({ input, returnValue }) => {
+ expect(safeTrim(input)).toEqual(returnValue);
+ });
+ });
+
describe('isEmptyValue', () => {
it.each`
input | returnValue
@@ -106,14 +127,102 @@ describe('lib/utils/forms', () => {
${[]} | ${true}
${null} | ${true}
${undefined} | ${true}
+ ${' '} | ${true}
${'hello'} | ${false}
- ${' '} | ${false}
${0} | ${false}
`('returns $returnValue for value $input', ({ input, returnValue }) => {
expect(isEmptyValue(input)).toBe(returnValue);
});
});
+ describe('hasMinimumLength', () => {
+ it.each`
+ input | minLength | returnValue
+ ${['o', 't']} | ${1} | ${true}
+ ${'hello'} | ${3} | ${true}
+ ${' '} | ${2} | ${false}
+ ${''} | ${0} | ${false}
+ ${''} | ${8} | ${false}
+ ${[]} | ${0} | ${false}
+ ${null} | ${8} | ${false}
+ ${undefined} | ${8} | ${false}
+ ${'hello'} | ${8} | ${false}
+ ${0} | ${8} | ${false}
+ ${4} | ${1} | ${false}
+ `(
+ 'returns $returnValue for value $input and minLength $minLength',
+ ({ input, minLength, returnValue }) => {
+ expect(hasMinimumLength(input, minLength)).toBe(returnValue);
+ },
+ );
+ });
+
+ describe('isPareseableInteger', () => {
+ it.each`
+ input | returnValue
+ ${'0'} | ${true}
+ ${'12'} | ${true}
+ ${''} | ${false}
+ ${[]} | ${false}
+ ${null} | ${false}
+ ${undefined} | ${false}
+ ${'hello'} | ${false}
+ ${' '} | ${false}
+ ${'12.4'} | ${false}
+ ${'12ef'} | ${false}
+ `('returns $returnValue for value $input', ({ input, returnValue }) => {
+ expect(isParseableAsInteger(input)).toBe(returnValue);
+ });
+ });
+
+ describe('isIntegerGreaterThan', () => {
+ it.each`
+ input | greaterThan | returnValue
+ ${25} | ${8} | ${true}
+ ${'25'} | ${8} | ${true}
+ ${'4'} | ${1} | ${true}
+ ${'4'} | ${8} | ${false}
+ ${'9.5'} | ${8} | ${false}
+ ${'9.5e'} | ${8} | ${false}
+ ${['o', 't']} | ${0} | ${false}
+ ${'hello'} | ${0} | ${false}
+ ${' '} | ${0} | ${false}
+ ${''} | ${0} | ${false}
+ ${''} | ${8} | ${false}
+ ${[]} | ${0} | ${false}
+ ${null} | ${0} | ${false}
+ ${undefined} | ${0} | ${false}
+ ${'hello'} | ${0} | ${false}
+ ${0} | ${0} | ${false}
+ `(
+ 'returns $returnValue for value $input and greaterThan $greaterThan',
+ ({ input, greaterThan, returnValue }) => {
+ expect(isIntegerGreaterThan(input, greaterThan)).toBe(returnValue);
+ },
+ );
+ });
+
+ describe('isEmail', () => {
+ it.each`
+ input | returnValue
+ ${'user-with_special-chars@example.com'} | ${true}
+ ${'user@subdomain.example.com'} | ${true}
+ ${'user@example.com'} | ${true}
+ ${'user@example.co'} | ${true}
+ ${'user@example.c'} | ${false}
+ ${'user@example'} | ${false}
+ ${''} | ${false}
+ ${[]} | ${false}
+ ${null} | ${false}
+ ${undefined} | ${false}
+ ${'hello'} | ${false}
+ ${' '} | ${false}
+ ${'12'} | ${false}
+ `('returns $returnValue for value $input', ({ input, returnValue }) => {
+ expect(isEmail(input)).toBe(returnValue);
+ });
+ });
+
describe('serializeFormObject', () => {
it('returns an serialized object', () => {
const form = {
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
index 9714093e001..85eb7e2e241 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/command_palette_items_spec.js
@@ -10,6 +10,7 @@ import {
USER_HANDLE,
PATH_HANDLE,
SEARCH_SCOPE,
+ MAX_ROWS,
} from '~/super_sidebar/components/global_search/command_palette/constants';
import {
commandMapper,
@@ -164,7 +165,26 @@ describe('CommandPaletteItems', () => {
expect(findLoader().exists()).toBe(true);
});
- it('should render returned items', async () => {
+ it(`should render all items when returned number of items is less than ${MAX_ROWS}`, async () => {
+ const numberOfItems = MAX_ROWS - 1;
+ const items = FILES.slice(0, numberOfItems).map(fileMapper.bind(null, projectBlobPath));
+ mockAxios.onGet().replyOnce(HTTP_STATUS_OK, FILES.slice(0, numberOfItems));
+ jest.spyOn(fuzzaldrinPlus, 'filter').mockReturnValue(items);
+
+ const searchQuery = 'gitlab-ci.yml';
+ createComponent({ handle: PATH_HANDLE, searchQuery });
+
+ await waitForPromises();
+
+ expect(findGroups().at(0).props('group')).toMatchObject({
+ name: PATH_GROUP_TITLE,
+ items: items.slice(0, MAX_ROWS),
+ });
+
+ expect(findItems()).toHaveLength(numberOfItems);
+ });
+
+ it(`should render first ${MAX_ROWS} returned items when number of returned items exceeds ${MAX_ROWS}`, async () => {
const items = FILES.map(fileMapper.bind(null, projectBlobPath));
mockAxios.onGet().replyOnce(HTTP_STATUS_OK, FILES);
jest.spyOn(fuzzaldrinPlus, 'filter').mockReturnValue(items);
@@ -174,10 +194,10 @@ describe('CommandPaletteItems', () => {
await waitForPromises();
- expect(findItems()).toHaveLength(items.length);
+ expect(findItems()).toHaveLength(MAX_ROWS);
expect(findGroups().at(0).props('group')).toMatchObject({
name: PATH_GROUP_TITLE,
- items,
+ items: items.slice(0, MAX_ROWS),
});
});
diff --git a/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
index 26a6501c338..d01e5c85741 100644
--- a/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
+++ b/spec/frontend/super_sidebar/components/global_search/command_palette/mock_data.js
@@ -133,13 +133,44 @@ export const ISSUE = {
};
export const FILES = [
- '.codeclimate.yml',
+ '.gitattributes',
'.gitignore',
- '.gitlab-ci.yml',
- '.gitlab/CODEOWNERS',
- '.ruby-version',
- '.tool-versions',
+ '.gitmodules',
'CHANGELOG',
'CONTRIBUTING.md',
- 'Dangerfile',
+ 'Gemfile.zip',
+ 'LICENSE',
+ 'MAINTENANCE.md',
+ 'PROCESS.md',
+ 'README',
+ 'README.md',
+ 'VERSION',
+ 'bar/branch-test.txt',
+ 'custom-highlighting/test.gitlab-custom',
+ 'encoding/feature-1.txt',
+ 'encoding/feature-2.txt',
+ 'encoding/hotfix-1.txt',
+ 'encoding/hotfix-2.txt',
+ 'encoding/iso8859.txt',
+ 'encoding/russian.rb',
+ 'encoding/test.txt',
+ 'encoding/テスト.txt',
+ 'encoding/テスト.xls',
+ 'files/flat/path/correct/content.txt',
+ 'files/html/500.html',
+ 'files/images/6049019_460s.jpg',
+ 'files/images/emoji.png',
+ 'files/images/logo-black.png',
+ 'files/images/logo-white.png',
+ 'files/images/wm.svg',
+ 'files/js/application.js',
+ 'files/js/commit.coffee',
+ 'files/lfs/lfs_object.iso',
+ 'files/markdown/ruby-style-guide.md',
+ 'files/ruby/popen.rb',
+ 'files/ruby/regex.rb',
+ 'files/ruby/version_info.rb',
+ 'files/whitespace',
+ 'foo/bar/.gitkeep',
+ 'with space/README.md',
];
diff --git a/spec/frontend/users/profile/actions/components/user_actions_app_spec.js b/spec/frontend/users/profile/actions/components/user_actions_app_spec.js
new file mode 100644
index 00000000000..d27962440ee
--- /dev/null
+++ b/spec/frontend/users/profile/actions/components/user_actions_app_spec.js
@@ -0,0 +1,38 @@
+import { GlDisclosureDropdown } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import UserActionsApp from '~/users/profile/actions/components/user_actions_app.vue';
+
+describe('User Actions App', () => {
+ let wrapper;
+
+ const USER_ID = 'test-id';
+
+ const createWrapper = (propsData = {}) => {
+ wrapper = mountExtended(UserActionsApp, {
+ propsData: {
+ userId: USER_ID,
+ ...propsData,
+ },
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
+ const findActions = () => wrapper.findAllByTestId('disclosure-dropdown-item');
+ const findAction = (position = 0) => findActions().at(position);
+
+ it('shows dropdown', () => {
+ createWrapper();
+ expect(findDropdown().exists()).toBe(true);
+ });
+
+ it('shows actions correctly', () => {
+ createWrapper();
+ expect(findActions()).toHaveLength(1);
+ });
+
+ it('shows copy user id action', () => {
+ createWrapper();
+ expect(findAction().text()).toBe(`Copy user ID: ${USER_ID}`);
+ expect(findAction().findComponent('button').attributes('data-clipboard-text')).toBe(USER_ID);
+ });
+});
diff --git a/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb b/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb
deleted file mode 100644
index 354fd350aa7..00000000000
--- a/spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::Metrics::DashboardResolver, feature_category: :metrics do
- include GraphqlHelpers
-
- let_it_be(:current_user) { create(:user) }
-
- describe '#resolve' do
- subject(:resolve_dashboard) { resolve(described_class, obj: parent_object, args: args, ctx: { current_user: current_user }) }
-
- let(:args) do
- {
- path: 'config/prometheus/common_metrics.yml'
- }
- end
-
- context 'for environment' do
- let(:project) { create(:project) }
- let(:parent_object) { create(:environment, project: project) }
-
- before do
- stub_feature_flags(remove_monitor_metrics: false)
- project.add_developer(current_user)
- end
-
- it 'use ActiveModel class to find matching dashboard', :aggregate_failures do
- expected_arguments = { project: project, user: current_user, path: args[:path], options: { environment: parent_object } }
-
- expect(PerformanceMonitoring::PrometheusDashboard).to receive(:find_for).with(expected_arguments).and_return(PerformanceMonitoring::PrometheusDashboard.new)
- expect(resolve_dashboard).to be_instance_of PerformanceMonitoring::PrometheusDashboard
- end
-
- context 'without parent object' do
- let(:parent_object) { nil }
-
- it 'returns nil', :aggregate_failures do
- expect(PerformanceMonitoring::PrometheusDashboard).not_to receive(:find_for)
- expect(resolve_dashboard).to be_nil
- end
- end
-
- context 'when metrics dashboard feature is unavailable' do
- before do
- stub_feature_flags(remove_monitor_metrics: true)
- end
-
- it 'returns nil', :aggregate_failures do
- expect(PerformanceMonitoring::PrometheusDashboard).not_to receive(:find_for)
- expect(resolve_dashboard).to be_nil
- end
- end
- end
- end
-end
diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb
index 721c20efc81..1d1bc4b2cb4 100644
--- a/spec/graphql/types/environment_type_spec.rb
+++ b/spec/graphql/types/environment_type_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe GitlabSchema.types['Environment'] do
it 'includes the expected fields' do
expected_fields = %w[
- name id state metrics_dashboard latest_opened_most_severe_alert path external_url deployments
+ name id state latest_opened_most_severe_alert path external_url deployments
slug createdAt updatedAt autoStopAt autoDeleteAt tier environmentType lastDeployment deployFreezes
clusterAgent
]
diff --git a/spec/graphql/types/metrics/dashboard_type_spec.rb b/spec/graphql/types/metrics/dashboard_type_spec.rb
deleted file mode 100644
index 114db87d5f1..00000000000
--- a/spec/graphql/types/metrics/dashboard_type_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GitlabSchema.types['MetricsDashboard'] do
- specify { expect(described_class.graphql_name).to eq('MetricsDashboard') }
-
- it 'has the expected fields' do
- expected_fields = %w[
- path annotations schema_validation_warnings
- ]
-
- expect(described_class).to have_graphql_fields(*expected_fields)
- end
-
- describe 'annotations field' do
- subject { described_class.fields['annotations'] }
-
- it { is_expected.to have_graphql_type(Types::Metrics::Dashboards::AnnotationType.connection_type) }
- it { is_expected.to have_graphql_resolver(Resolvers::Metrics::Dashboards::AnnotationResolver) }
- end
-end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index ffaffa251d1..a2b8ee061bb 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -666,9 +666,11 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
describe '#sidebar_milestone_tooltip_label' do
it 'escapes HTML in the milestone title' do
- milestone = build(:milestone, title: '&lt;img onerror=alert(1)&gt;')
+ milestone = build(:milestone, title: '&lt;img onerror=alert(1)&gt;', due_date: Date.new(2022, 6, 26))
- expect(helper.sidebar_milestone_tooltip_label(milestone)).to eq('&lt;img onerror=alert(1)&gt;<br/>Milestone')
+ expect(helper.sidebar_milestone_tooltip_label(milestone)).to eq(
+ '&lt;img onerror=alert(1)&gt;<br/>Jun 26, 2022 (<strong>Past due</strong>)'
+ )
end
end
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index b14789fd5d2..43500d98591 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -270,7 +270,7 @@ RSpec.describe PageLayoutHelper do
it 'merges the status properties with the defaults' do
is_expected.to eq({
- current_clear_status_after: time.to_s(:iso8601),
+ current_clear_status_after: time.to_fs(:iso8601),
current_availability: 'busy',
current_emoji: 'basketball',
current_message: 'Some message',
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb
index 773df9b20ee..56fef37f939 100644
--- a/spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/keyset/connection_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::Connection do
let(:nodes) { Project.all.order(Gitlab::Pagination::Keyset::Order.build([column_order_updated_at, column_order_created_at, column_order_id])) }
it 'returns the encoded value of the order' do
- expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_s(:inspect))
+ expect(decoded_cursor(cursor)).to include('updated_at' => project.updated_at.to_fs(:inspect))
end
end
end
diff --git a/spec/lib/gitlab/manifest_import/metadata_spec.rb b/spec/lib/gitlab/manifest_import/metadata_spec.rb
index c8158d3e148..17cc0425ca7 100644
--- a/spec/lib/gitlab/manifest_import/metadata_spec.rb
+++ b/spec/lib/gitlab/manifest_import/metadata_spec.rb
@@ -12,51 +12,98 @@ RSpec.describe Gitlab::ManifestImport::Metadata, :clean_gitlab_redis_shared_stat
end
describe '#save' do
- it 'stores data in Redis with an expiry of EXPIRY_TIME' do
- status = described_class.new(user)
- repositories_key = 'manifest_import:metadata:user:1:repositories'
- group_id_key = 'manifest_import:metadata:user:1:group_id'
+ let(:status) { described_class.new(user) }
+ let(:hashtag_repositories_key) { 'manifest_import:metadata:user:{1}:repositories' }
+ let(:hashtag_group_id_key) { 'manifest_import:metadata:user:{1}:group_id' }
+ let(:repositories_key) { 'manifest_import:metadata:user:1:repositories' }
+ let(:group_id_key) { 'manifest_import:metadata:user:1:group_id' }
+
+ subject { status.save(repositories, 2) }
- status.save(repositories, 2)
+ it 'stores data in Redis with an expiry of EXPIRY_TIME' do
+ subject
Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.ttl(hashtag_repositories_key)).to be_within(5).of(described_class::EXPIRY_TIME)
+ expect(redis.ttl(hashtag_group_id_key)).to be_within(5).of(described_class::EXPIRY_TIME)
expect(redis.ttl(repositories_key)).to be_within(5).of(described_class::EXPIRY_TIME)
expect(redis.ttl(group_id_key)).to be_within(5).of(described_class::EXPIRY_TIME)
end
end
+
+ context 'with `manifest_import_use_hash_tagged_key`feature flag disabled' do
+ before do
+ stub_feature_flags(manifest_import_use_hash_tagged_key: false)
+ end
+
+ it 'only stores Redis String' do
+ subject
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.ttl(hashtag_repositories_key)).to eq(-2)
+ expect(redis.ttl(hashtag_group_id_key)).to eq(-2)
+ expect(redis.ttl(repositories_key)).to be_within(5).of(described_class::EXPIRY_TIME)
+ expect(redis.ttl(group_id_key)).to be_within(5).of(described_class::EXPIRY_TIME)
+ end
+ end
+ end
end
describe '#repositories' do
- it 'allows repositories to round-trip with symbol keys' do
- status = described_class.new(user)
+ shared_examples 'read repositories' do
+ it 'allows repositories to round-trip with symbol keys' do
+ status = described_class.new(user)
- status.save(repositories, 2)
+ status.save(repositories, 2)
+
+ expect(status.repositories).to eq(repositories)
+ end
- expect(status.repositories).to eq(repositories)
+ it 'uses the fallback when there is nothing in Redis' do
+ fallback = { manifest_import_repositories: repositories }
+ status = described_class.new(user, fallback: fallback)
+
+ expect(status.repositories).to eq(repositories)
+ end
end
- it 'uses the fallback when there is nothing in Redis' do
- fallback = { manifest_import_repositories: repositories }
- status = described_class.new(user, fallback: fallback)
+ context 'with `manifest_import_use_hash_tagged_key` feature flag disabled' do
+ before do
+ stub_feature_flags(manifest_import_use_hash_tagged_key: false)
+ end
- expect(status.repositories).to eq(repositories)
+ it_behaves_like 'read repositories'
end
+
+ it_behaves_like 'read repositories'
end
describe '#group_id' do
- it 'returns the group ID as an integer' do
- status = described_class.new(user)
+ shared_examples 'read group_id' do
+ it 'returns the group ID as an integer' do
+ status = described_class.new(user)
+
+ status.save(repositories, 2)
- status.save(repositories, 2)
+ expect(status.group_id).to eq(2)
+ end
+
+ it 'uses the fallback when there is nothing in Redis' do
+ fallback = { manifest_import_group_id: 3 }
+ status = described_class.new(user, fallback: fallback)
- expect(status.group_id).to eq(2)
+ expect(status.group_id).to eq(3)
+ end
end
- it 'uses the fallback when there is nothing in Redis' do
- fallback = { manifest_import_group_id: 3 }
- status = described_class.new(user, fallback: fallback)
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(manifest_import_use_hash_tagged_key: false)
+ end
- expect(status.group_id).to eq(3)
+ it_behaves_like 'read group_id'
end
+
+ it_behaves_like 'read group_id'
end
end
diff --git a/spec/lib/gitlab/pagination/keyset/iterator_spec.rb b/spec/lib/gitlab/pagination/keyset/iterator_spec.rb
index eee743c5e48..afaad48d363 100644
--- a/spec/lib/gitlab/pagination/keyset/iterator_spec.rb
+++ b/spec/lib/gitlab/pagination/keyset/iterator_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do
time = Time.current
iterator.each_batch(of: 2) do |relation|
- Issue.connection.execute("UPDATE issues SET updated_at = '#{time.to_s(:inspect)}' WHERE id IN (#{relation.reselect(:id).to_sql})")
+ Issue.connection.execute("UPDATE issues SET updated_at = '#{time.to_fs(:inspect)}' WHERE id IN (#{relation.reselect(:id).to_sql})")
end
expect(Issue.pluck(:updated_at)).to all(be_within(5.seconds).of(time))
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
index 993edcab87d..c22e7a1240f 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
@@ -226,6 +226,14 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
expect(redis_ttl(cookie_key)).to be_within(1).of(expected_ttl)
end
+ it 'does not try to set an invalid ttl at the end of expiry' do
+ with_redis { |r| r.expire(cookie_key, 1) }
+
+ sleep 0.5 # sleep 500ms to redis would round the remaining ttl to 0
+
+ expect { subject }.not_to raise_error
+ end
+
context 'and low offsets' do
let(:existing_cookie) do
{
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
index 317929f77e6..eee5396bdbf 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_bulk_imports_entities_metric_spec.rb
@@ -30,8 +30,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 6 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\
" WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"
@@ -63,8 +63,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 3 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\
" WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"\
@@ -92,8 +92,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 3 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\
" WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"\
@@ -121,8 +121,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 4 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\
" WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"\
@@ -150,8 +150,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 2 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\""\
" WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"\
@@ -202,8 +202,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
let(:expected_value) { 3 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
"WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
@@ -249,8 +249,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'for 28d time frame' do
context 'with project entity' do
let(:expected_value) { 2 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
"WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
@@ -265,8 +265,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountBulkImportsEntitie
context 'with group entity' do
let(:expected_value) { 2 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"bulk_import_entities\".\"id\") FROM \"bulk_import_entities\" " \
"WHERE \"bulk_import_entities\".\"created_at\" BETWEEN '#{start}' AND '#{finish}' " \
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
index b7da9b27e19..8ae64e8db23 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_metric_spec.rb
@@ -43,8 +43,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsMe
context 'for 28d time frame' do
let(:expected_value) { 3 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"projects\".\"id\") FROM \"projects\" WHERE \"projects\".\"created_at\""\
" BETWEEN '#{start}' AND '#{finish}' AND \"projects\".\"import_type\" = 'gitea'"
@@ -70,8 +70,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsMe
context 'for 28d time frame' do
let(:expected_value) { 2 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT COUNT(\"projects\".\"id\") FROM \"projects\" WHERE \"projects\".\"created_at\""\
" BETWEEN '#{start}' AND '#{finish}' AND \"projects\".\"import_type\" = 'bitbucket'"
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb
index bfc4240def6..bd432b614e7 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_imported_projects_total_metric_spec.rb
@@ -45,8 +45,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountImportedProjectsTo
context 'for 28d time frame' do
let(:expected_value) { 8 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) do
"SELECT (SELECT COUNT(\"projects\".\"id\") FROM \"projects\" WHERE \"projects\".\"import_type\""\
" IN ('gitlab_project', 'gitlab', 'github', 'bitbucket', 'bitbucket_server', 'gitea', 'git', 'manifest',"\
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb
index 3fb4c3a4e3f..86aa37b494a 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_issues_metric_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountUsersCreatingIssue
context 'for 28d time frame' do
let(:expected_value) { 1 }
- let(:start) { 30.days.ago.to_s(:db) }
- let(:finish) { 2.days.ago.to_s(:db) }
+ let(:start) { 30.days.ago.to_fs(:db) }
+ let(:finish) { 2.days.ago.to_fs(:db) }
let(:expected_query) { "SELECT COUNT(DISTINCT \"issues\".\"author_id\") FROM \"issues\" WHERE \"issues\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'" }
it_behaves_like 'a correct instrumented metric value and query', { time_frame: '28d' }
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 46a876f34e9..01efe66a419 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -356,4 +356,20 @@ RSpec.describe Milestone, 'Milestoneish', factory_default: :keep do
expect(milestone.human_total_time_estimate).to be_nil
end
end
+
+ describe '#expires_at' do
+ it 'returns the date when milestone expires' do
+ due_date = Date.today + 1.day
+ milestone.due_date = due_date
+
+ expect(milestone.expires_at).to eq("expires on #{due_date.to_fs(:medium)}")
+ end
+
+ it 'returns the date when milestone expires' do
+ due_date = Date.today - 1.day
+ milestone.due_date = due_date
+
+ expect(milestone.expires_at).to eq("expired on #{due_date.to_fs(:medium)}")
+ end
+ end
end
diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb
index 9f2c692287e..7fcd74cd37f 100644
--- a/spec/models/integration_spec.rb
+++ b/spec/models/integration_spec.rb
@@ -1362,5 +1362,17 @@ RSpec.describe Integration, feature_category: :integrations do
async_execute
end
end
+
+ context 'when the Gitlab::SilentMode is enabled' do
+ before do
+ allow(Gitlab::SilentMode).to receive(:enabled?).and_return(true)
+ end
+
+ it 'does not queue a worker' do
+ expect(Integrations::ExecuteWorker).not_to receive(:perform_async)
+
+ async_execute
+ end
+ end
end
end
diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb
index e56ff2241b1..05e10fd6763 100644
--- a/spec/models/protected_branch/push_access_level_spec.rb
+++ b/spec/models/protected_branch/push_access_level_spec.rb
@@ -4,81 +4,6 @@ require 'spec_helper'
RSpec.describe ProtectedBranch::PushAccessLevel, feature_category: :source_code_management do
include_examples 'protected branch access'
+ include_examples 'protected ref deploy_key access'
include_examples 'protected ref access allowed_access_levels'
-
- describe 'associations' do
- it { is_expected.to belong_to(:deploy_key) }
- end
-
- describe 'validations' do
- it 'is not valid when a record exists with the same access level' do
- protected_branch = create(:protected_branch)
- create(:protected_branch_push_access_level, protected_branch: protected_branch)
- level = build(:protected_branch_push_access_level, protected_branch: protected_branch)
-
- expect(level).to be_invalid
- end
-
- it 'is not valid when a record exists with the same access level' do
- protected_branch = create(:protected_branch)
- deploy_key = create(:deploy_key, projects: [protected_branch.project])
- create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key)
- level = build(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key)
-
- expect(level).to be_invalid
- end
-
- it 'checks that a deploy key is enabled for the same project as the protected branch\'s' do
- level = build(:protected_branch_push_access_level, deploy_key: create(:deploy_key))
-
- expect { level.save! }.to raise_error(ActiveRecord::RecordInvalid)
- expect(level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
- end
- end
-
- describe '#check_access' do
- let_it_be(:project) { create(:project) }
- let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push, project: project) }
- let_it_be(:user) { create(:user) }
- let_it_be(:deploy_key) { create(:deploy_key, user: user) }
-
- let!(:deploy_keys_project) { create(:deploy_keys_project, project: project, deploy_key: deploy_key, can_push: can_push) }
- let(:can_push) { true }
-
- before_all do
- project.add_maintainer(user)
- end
-
- context 'when this push_access_level is tied to a deploy key' do
- let(:push_access_level) { create(:protected_branch_push_access_level, protected_branch: protected_branch, deploy_key: deploy_key) }
-
- context 'when the deploy key is among the active keys for this project' do
- specify do
- expect(push_access_level.check_access(user)).to be_truthy
- end
- end
-
- context 'when the deploy key is not among the active keys of this project' do
- let(:can_push) { false }
-
- it 'is false' do
- expect(push_access_level.check_access(user)).to be_falsey
- end
- end
- end
- end
-
- describe '#type' do
- let(:push_level_access) { build(:protected_branch_push_access_level) }
-
- it 'returns :deploy_key when a deploy key is tied to the protected branch' do
- push_level_access.deploy_key = create(:deploy_key)
-
- expect(push_level_access.type).to eq(:deploy_key)
- end
-
- it 'returns :role by default' do
- expect(push_level_access.type).to eq(:role)
- end
- end
end
diff --git a/spec/models/protected_tag/create_access_level_spec.rb b/spec/models/protected_tag/create_access_level_spec.rb
index 8eeccdc9b34..d795399060e 100644
--- a/spec/models/protected_tag/create_access_level_spec.rb
+++ b/spec/models/protected_tag/create_access_level_spec.rb
@@ -4,134 +4,6 @@ require 'spec_helper'
RSpec.describe ProtectedTag::CreateAccessLevel, feature_category: :source_code_management do
include_examples 'protected tag access'
+ include_examples 'protected ref deploy_key access'
include_examples 'protected ref access allowed_access_levels'
-
- describe 'associations' do
- it { is_expected.to belong_to(:deploy_key) }
- end
-
- describe 'validations', :aggregate_failures do
- let_it_be(:protected_tag) { create(:protected_tag) }
-
- context 'when deploy key enabled for the project' do
- let(:deploy_key) { create(:deploy_key, projects: [protected_tag.project]) }
-
- it 'is valid' do
- level = build(:protected_tag_create_access_level, protected_tag: protected_tag, deploy_key: deploy_key)
-
- expect(level).to be_valid
- end
- end
-
- context 'when a record exists with the same access level' do
- before do
- create(:protected_tag_create_access_level, protected_tag: protected_tag)
- end
-
- it 'is not valid' do
- level = build(:protected_tag_create_access_level, protected_tag: protected_tag)
-
- expect(level).to be_invalid
- expect(level.errors.full_messages).to include('Access level has already been taken')
- end
- end
-
- context 'when a deploy key already added for this access level' do
- let!(:create_access_level) do
- create(:protected_tag_create_access_level, protected_tag: protected_tag, deploy_key: deploy_key)
- end
-
- let(:deploy_key) { create(:deploy_key, projects: [protected_tag.project]) }
-
- it 'is not valid' do
- level = build(:protected_tag_create_access_level, protected_tag: protected_tag, deploy_key: deploy_key)
-
- expect(level).to be_invalid
- expect(level.errors.full_messages).to contain_exactly('Deploy key has already been taken')
- end
- end
-
- context 'when deploy key is not enabled for the project' do
- let(:create_access_level) do
- build(:protected_tag_create_access_level, protected_tag: protected_tag, deploy_key: create(:deploy_key))
- end
-
- it 'returns an error' do
- expect(create_access_level).to be_invalid
- expect(create_access_level.errors.full_messages).to contain_exactly(
- 'Deploy key is not enabled for this project'
- )
- end
- end
- end
-
- describe '#check_access' do
- let_it_be(:project) { create(:project) }
- let_it_be(:protected_tag) { create(:protected_tag, :no_one_can_create, project: project) }
- let_it_be(:user) { create(:user) }
- let_it_be(:deploy_key) { create(:deploy_key, user: user) }
-
- let!(:deploy_keys_project) do
- create(:deploy_keys_project, project: project, deploy_key: deploy_key, can_push: can_push)
- end
-
- let(:create_access_level) { protected_tag.create_access_levels.first }
- let(:can_push) { true }
-
- before_all do
- project.add_maintainer(user)
- end
-
- it { expect(create_access_level.check_access(user)).to be_falsey }
-
- context 'when this create_access_level is tied to a deploy key' do
- let(:create_access_level) do
- create(:protected_tag_create_access_level, protected_tag: protected_tag, deploy_key: deploy_key)
- end
-
- context 'when the deploy key is among the active keys for this project' do
- it { expect(create_access_level.check_access(user)).to be_truthy }
- end
-
- context 'when user is missing' do
- it { expect(create_access_level.check_access(nil)).to be_falsey }
- end
-
- context 'when deploy key does not belong to the user' do
- let(:another_user) { create(:user) }
-
- it { expect(create_access_level.check_access(another_user)).to be_falsey }
- end
-
- context 'when user cannot access the project' do
- before do
- allow(user).to receive(:can?).with(:read_project, project).and_return(false)
- end
-
- it { expect(create_access_level.check_access(user)).to be_falsey }
- end
-
- context 'when the deploy key is not among the active keys of this project' do
- let(:can_push) { false }
-
- it { expect(create_access_level.check_access(user)).to be_falsey }
- end
- end
- end
-
- describe '#type' do
- let(:create_access_level) { build(:protected_tag_create_access_level) }
-
- it 'returns :role by default' do
- expect(create_access_level.type).to eq(:role)
- end
-
- context 'when a deploy key is tied to the protected branch' do
- let(:create_access_level) { build(:protected_tag_create_access_level, deploy_key: build(:deploy_key)) }
-
- it 'returns :deploy_key' do
- expect(create_access_level.type).to eq(:deploy_key)
- end
- end
- end
end
diff --git a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb
deleted file mode 100644
index 143bc1672f8..00000000000
--- a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Getting Metrics Dashboard Annotations', feature_category: :metrics do
- include GraphqlHelpers
-
- let_it_be(:project) { create(:project) }
- let_it_be(:environment) { create(:environment, project: project) }
- let_it_be(:current_user) { create(:user) }
- let_it_be(:path) { 'config/prometheus/common_metrics.yml' }
- let_it_be(:from) { "2020-04-01T03:29:25Z" }
- let_it_be(:to) { Time.zone.now.advance(minutes: 5) }
- let_it_be(:annotation) { create(:metrics_dashboard_annotation, environment: environment, dashboard_path: path) }
- let_it_be(:annotation_for_different_env) { create(:metrics_dashboard_annotation, dashboard_path: path) }
- let_it_be(:annotation_for_different_dashboard) { create(:metrics_dashboard_annotation, environment: environment, dashboard_path: ".gitlab/dashboards/test.yml") }
- let_it_be(:to_old_annotation) do
- create(:metrics_dashboard_annotation, environment: environment, starting_at: Time.parse(from).advance(minutes: -5), dashboard_path: path)
- end
-
- let_it_be(:to_new_annotation) do
- create(:metrics_dashboard_annotation, environment: environment, starting_at: to.advance(minutes: 5), dashboard_path: path)
- end
-
- let(:remove_monitor_metrics) { false }
- let(:args) { "from: \"#{from}\", to: \"#{to}\"" }
- let(:fields) do
- <<~QUERY
- #{all_graphql_fields_for('MetricsDashboardAnnotation'.classify)}
- QUERY
- end
-
- let(:query) do
- %(
- query {
- project(fullPath: "#{project.full_path}") {
- environments(name: "#{environment.name}") {
- nodes {
- metricsDashboard(path: "#{path}") {
- annotations(#{args}) {
- nodes {
- #{fields}
- }
- }
- }
- }
- }
- }
- }
- )
- end
-
- before do
- stub_feature_flags(remove_monitor_metrics: remove_monitor_metrics)
- project.add_developer(current_user)
- post_graphql(query, current_user: current_user)
- end
-
- it_behaves_like 'a working graphql query'
-
- it 'returns annotations' do
- annotations = graphql_data.dig('project', 'environments', 'nodes')[0].dig('metricsDashboard', 'annotations', 'nodes')
-
- expect(annotations).to match_array [{
- "description" => annotation.description,
- "id" => annotation.to_global_id.to_s,
- "panelId" => annotation.panel_xid,
- "startingAt" => annotation.starting_at.iso8601,
- "endingAt" => nil
- }]
- end
-
- context 'arguments' do
- context 'from is missing' do
- let(:args) { "to: \"#{from}\"" }
-
- it 'returns error' do
- post_graphql(query, current_user: current_user)
-
- expect(graphql_errors[0]).to include("message" => "Field 'annotations' is missing required arguments: from")
- end
- end
-
- context 'to is missing' do
- let(:args) { "from: \"#{from}\"" }
-
- it_behaves_like 'a working graphql query'
- end
- end
-
- context 'when metrics dashboard feature is unavailable' do
- let(:remove_monitor_metrics) { true }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns nil' do
- annotations = graphql_data.dig(
- 'project', 'environments', 'nodes', 0, 'metricsDashboard', 'annotations'
- )
-
- expect(annotations).to be_nil
- end
- end
-end
diff --git a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb b/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
deleted file mode 100644
index b7d9b59f5fe..00000000000
--- a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
+++ /dev/null
@@ -1,114 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Getting Metrics Dashboard', feature_category: :metrics do
- include GraphqlHelpers
-
- let_it_be(:current_user) { create(:user) }
-
- let(:project) { create(:project) }
- let(:environment) { create(:environment, project: project) }
-
- let(:query) do
- graphql_query_for(
- 'project', { 'fullPath' => project.full_path },
- query_graphql_field(
- :environments, { 'name' => environment.name },
- query_graphql_field(
- :nodes, nil,
- query_graphql_field(
- :metricsDashboard, { 'path' => path },
- all_graphql_fields_for('MetricsDashboard'.classify)
- )
- )
- )
- )
- end
-
- context 'for anonymous user' do
- before do
- post_graphql(query, current_user: current_user)
- end
-
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes')
-
- expect(dashboard).to be_nil
- end
- end
- end
-
- context 'for user with developer access' do
- let(:remove_monitor_metrics) { false }
-
- before do
- stub_feature_flags(remove_monitor_metrics: remove_monitor_metrics)
- project.add_developer(current_user)
- post_graphql(query, current_user: current_user)
- end
-
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => nil)
- end
-
- context 'invalid dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "---\ndashboard: 'test'" }) }
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["panel_groups: should be an array of panel_groups objects"])
- end
- end
-
- context 'empty dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "" }) }
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["dashboard: can't be blank", "panel_groups: should be an array of panel_groups objects"])
- end
- end
-
- context 'metrics dashboard feature is unavailable' do
- let(:remove_monitor_metrics) { true }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to be_nil
- end
- end
- end
-
- context 'requested dashboard can not be found' do
- let(:path) { 'config/prometheus/i_am_not_here.yml' }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to be_nil
- end
- end
- end
-end
diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb
index 71228050085..a3793880ff1 100644
--- a/spec/services/system_notes/time_tracking_service_spec.rb
+++ b/spec/services/system_notes/time_tracking_service_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
context 'when both dates are added' do
it 'sets the correct note message' do
- expect(note.note).to eq("changed start date to #{start_date.to_s(:long)} and changed due date to #{due_date.to_s(:long)}")
+ expect(note.note).to eq("changed start date to #{start_date.to_fs(:long)} and changed due date to #{due_date.to_fs(:long)}")
end
end
@@ -37,7 +37,7 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
end
it 'sets the correct note message' do
- expect(note.note).to eq("removed start date #{start_date.to_s(:long)} and removed due date #{due_date.to_s(:long)}")
+ expect(note.note).to eq("removed start date #{start_date.to_fs(:long)} and removed due date #{due_date.to_fs(:long)}")
end
end
@@ -45,14 +45,14 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
let(:changed_dates) { { 'due_date' => [nil, due_date] } }
it 'sets the correct note message' do
- expect(note.note).to eq("changed due date to #{due_date.to_s(:long)}")
+ expect(note.note).to eq("changed due date to #{due_date.to_fs(:long)}")
end
context 'and start date removed' do
let(:changed_dates) { { 'due_date' => [nil, due_date], 'start_date' => [start_date, nil] } }
it 'sets the correct note message' do
- expect(note.note).to eq("removed start date #{start_date.to_s(:long)} and changed due date to #{due_date.to_s(:long)}")
+ expect(note.note).to eq("removed start date #{start_date.to_fs(:long)} and changed due date to #{due_date.to_fs(:long)}")
end
end
end
@@ -73,14 +73,14 @@ RSpec.describe ::SystemNotes::TimeTrackingService, feature_category: :team_plann
end
it 'sets the correct note message' do
- expect(note.note).to eq("changed start date to #{start_date.to_s(:long)}")
+ expect(note.note).to eq("changed start date to #{start_date.to_fs(:long)}")
end
context 'and due date removed' do
let(:changed_dates) { { 'due_date' => [due_date, nil], 'start_date' => [nil, start_date] } }
it 'sets the correct note message' do
- expect(note.note).to eq("changed start date to #{start_date.to_s(:long)} and removed due date #{due_date.to_s(:long)}")
+ expect(note.note).to eq("changed start date to #{start_date.to_fs(:long)} and removed due date #{due_date.to_fs(:long)}")
end
end
end
diff --git a/spec/services/work_items/export_csv_service_spec.rb b/spec/services/work_items/export_csv_service_spec.rb
index 948ff89245e..4566289231f 100644
--- a/spec/services/work_items/export_csv_service_spec.rb
+++ b/spec/services/work_items/export_csv_service_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe WorkItems::ExportCsvService, :with_license, feature_category: :te
end
specify 'created_at' do
- expect(csv[0]['Created At (UTC)']).to eq(work_item_1.created_at.to_s(:csv))
+ expect(csv[0]['Created At (UTC)']).to eq(work_item_1.created_at.to_fs(:csv))
end
specify 'description' do
diff --git a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
index 6f104f400bc..52f0e7847b0 100644
--- a/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
+++ b/spec/support/shared_examples/models/concerns/analytics/cycle_analytics/stage_event_model_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'StageEventModel' do
describe '.upsert_data' do
- let(:time) { Time.parse(Time.current.to_s(:db)) } # truncating the timestamp so we can compare it with the timestamp loaded from the DB
+ let(:time) { Time.parse(Time.current.to_fs(:db)) } # truncating the timestamp so we can compare it with the timestamp loaded from the DB
let(:input_data) do
[
{
diff --git a/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb b/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
index 4753d7a4556..0e9200f1fd9 100644
--- a/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
+++ b/spec/support/shared_examples/models/concerns/protected_ref_access_examples.rb
@@ -6,16 +6,34 @@ RSpec.shared_examples 'protected ref access' do |association|
let_it_be(:project) { create(:project) }
let_it_be(:protected_ref) { create(association, project: project) } # rubocop:disable Rails/SaveBang
- it { is_expected.to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
+ describe 'validations' do
+ subject { build(described_class.model_name.singular) }
- it { is_expected.to validate_presence_of(:access_level) }
+ context 'when role?' do
+ it { is_expected.to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
- context 'when not role?' do
- before do
- allow(subject).to receive(:role?).and_return(false)
+ it { is_expected.to validate_presence_of(:access_level) }
+
+ it do
+ is_expected.to validate_uniqueness_of(:access_level)
+ .scoped_to("#{described_class.module_parent.model_name.singular}_id")
+ end
end
- it { is_expected.not_to validate_presence_of(:access_level) }
+ context 'when not role?' do
+ before do
+ allow(subject).to receive(:role?).and_return(false)
+ end
+
+ it { is_expected.not_to validate_presence_of(:access_level) }
+
+ it { is_expected.not_to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
+
+ it do
+ is_expected.not_to validate_uniqueness_of(:access_level)
+ .scoped_to("#{described_class.module_parent.model_name.singular}_id")
+ end
+ end
end
describe '::human_access_levels' do
diff --git a/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb b/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb
new file mode 100644
index 00000000000..f2e79dc377b
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/protected_ref_deploy_key_access_examples.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'protected ref deploy_key access' do
+ let_it_be(:described_instance) { described_class.model_name.singular }
+ let_it_be(:protected_ref_name) { described_class.module_parent.model_name.singular }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:protected_ref) { create(protected_ref_name, project: project) } # rubocop:disable Rails/SaveBang
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:deploy_key) }
+ end
+
+ describe 'validations' do
+ context 'when deploy_key?' do
+ context 'when deploy key enabled for the project' do
+ let(:deploy_key) do
+ create(:deploy_keys_project, :write_access, project: project).deploy_key
+ end
+
+ it 'is valid' do
+ level = build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+
+ expect(level).to be_valid
+ end
+ end
+
+ context 'when a deploy key already added for this access level' do
+ let(:deploy_key) { create(:deploy_keys_project, :write_access, project: project).deploy_key }
+
+ before do
+ create(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ subject(:access_level) do
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key has already been taken')
+ end
+ end
+
+ context 'when deploy key is not enabled for the project' do
+ subject(:access_level) do
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: create(:deploy_key))
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
+ end
+ end
+
+ context 'when deploy key is not active for the project' do
+ subject(:access_level) do
+ deploy_key = create(:deploy_keys_project, :readonly_access, project: project).deploy_key
+ build(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ it 'is not valid', :aggregate_failures do
+ is_expected.to be_invalid
+ expect(access_level.errors.full_messages).to contain_exactly('Deploy key is not enabled for this project')
+ end
+ end
+ end
+ end
+
+ describe '#check_access' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:deploy_key) { create(:deploy_key, user: user) }
+ let_it_be(:deploy_keys_project) do
+ create(:deploy_keys_project, :write_access, project: project, deploy_key: deploy_key)
+ end
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ context "when this #{described_class.model_name.singular} is tied to a deploy key" do
+ let!(:access_level) do
+ create(described_instance, protected_ref_name => protected_ref, deploy_key: deploy_key)
+ end
+
+ context 'when the deploy key is among the active keys for this project' do
+ it { expect(access_level.check_access(user)).to be_truthy }
+ end
+
+ context 'when user is missing' do
+ it { expect(access_level.check_access(nil)).to be_falsey }
+ end
+
+ context 'when deploy key does not belong to the user' do
+ let(:another_user) { create(:user) }
+
+ it { expect(access_level.check_access(another_user)).to be_falsey }
+ end
+
+ context 'when user cannot access the project' do
+ before do
+ allow(user).to receive(:can?).with(:read_project, project).and_return(false)
+ end
+
+ it { expect(access_level.check_access(user)).to be_falsey }
+ end
+
+ context 'when the deploy key is not among the active keys of this project' do
+ before do
+ deploy_keys_project.update!(can_push: false)
+ end
+
+ after do
+ deploy_keys_project.update!(can_push: true)
+ end
+
+ it { expect(access_level.check_access(user)).to be_falsey }
+ end
+ end
+ end
+
+ describe '#type' do
+ let(:access_level) { build(described_instance) }
+
+ context 'when deploy_key?' do
+ let(:access_level) { build(described_instance, deploy_key: build(:deploy_key)) }
+
+ it 'returns :deploy_key' do
+ expect(access_level.type).to eq(:deploy_key)
+ end
+ end
+ end
+end
diff --git a/spec/views/profiles/show.html.haml_spec.rb b/spec/views/profiles/show.html.haml_spec.rb
index ea0a9ebb02c..e88b1bf4053 100644
--- a/spec/views/profiles/show.html.haml_spec.rb
+++ b/spec/views/profiles/show.html.haml_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'profiles/show' do
)
expect(rendered).to have_field(
'user[status][clear_status_after]',
- with: user_status.clear_status_at.to_s(:iso8601),
+ with: user_status.clear_status_at.to_fs(:iso8601),
type: :hidden
)
end
diff --git a/spec/workers/integrations/execute_worker_spec.rb b/spec/workers/integrations/execute_worker_spec.rb
index 717e3c65820..369fc5fd091 100644
--- a/spec/workers/integrations/execute_worker_spec.rb
+++ b/spec/workers/integrations/execute_worker_spec.rb
@@ -36,4 +36,18 @@ RSpec.describe Integrations::ExecuteWorker, '#perform', feature_category: :integ
end.not_to raise_error
end
end
+
+ context 'when the Gitlab::SilentMode is enabled' do
+ before do
+ allow(Gitlab::SilentMode).to receive(:enabled?).and_return(true)
+ end
+
+ it 'completes silently and does not log an error' do
+ expect(Gitlab::IntegrationsLogger).not_to receive(:error)
+
+ expect do
+ worker.perform(non_existing_record_id, {})
+ end.not_to raise_error
+ end
+ end
end