diff options
Diffstat (limited to 'spec')
9 files changed, 200 insertions, 10 deletions
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb index d899e86ae5f..8257e8d33b2 100644 --- a/spec/controllers/admin/clusters_controller_spec.rb +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -171,6 +171,29 @@ RSpec.describe Admin::ClustersController do end end + describe 'GET #prometheus_proxy' do + let(:user) { admin } + let(:proxyable) do + create(:cluster, :instance, :provided_by_gcp) + end + + it_behaves_like 'metrics dashboard prometheus api proxy' do + context 'with anonymous user' do + let(:prometheus_body) { nil } + + before do + sign_out(admin) + end + + it 'returns 404' do + get :prometheus_proxy, params: prometheus_proxy_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + describe 'POST #create_gcp' do let(:legacy_abac_param) { 'true' } let(:params) do diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index 6765cf0990a..bd6c976b003 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -192,6 +192,35 @@ RSpec.describe Groups::ClustersController do end end + describe 'GET #prometheus_proxy' do + let(:proxyable) do + create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group]) + end + + it_behaves_like 'metrics dashboard prometheus api proxy' do + let(:proxyable_params) do + { + id: proxyable.id.to_s, + group_id: group.name + } + end + + context 'with anonymous user' do + let(:prometheus_body) { nil } + + before do + sign_out(user) + end + + it 'returns 404' do + get :prometheus_proxy, params: prometheus_proxy_params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + end + describe 'POST create for new cluster' do let(:legacy_abac_param) { 'true' } let(:params) do diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index 5645e25b741..fc4657dafd9 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -200,6 +200,36 @@ RSpec.describe Projects::ClustersController do end end + describe 'GET #prometheus_proxy' do + let(:proxyable) do + create(:cluster, :provided_by_gcp, projects: [project]) + end + + it_behaves_like 'metrics dashboard prometheus api proxy' do + let(:proxyable_params) do + { + id: proxyable.id.to_s, + namespace_id: project.namespace.full_path, + project_id: project.name + } + end + + context 'with anonymous user' do + let(:prometheus_body) { nil } + + before do + sign_out(user) + end + + it 'redirects to signin page' do + get :prometheus_proxy, params: prometheus_proxy_params + + expect(response).to redirect_to(new_user_session_path) + end + end + end + end + describe 'POST create for new cluster' do let(:legacy_abac_param) { 'true' } let(:params) do diff --git a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js index 833208c2a35..9af26b31847 100644 --- a/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js +++ b/spec/frontend/registry/explorer/components/details_page/tags_list_row_spec.js @@ -54,6 +54,14 @@ describe('tags list row', () => { expect(findCheckbox().exists()).toBe(true); }); + it("does not exist when the row can't be deleted", () => { + const customTag = { ...tag, destroy_path: '' }; + + mountComponent({ ...defaultProps, tag: customTag }); + + expect(findCheckbox().exists()).toBe(false); + }); + it('is wired to the selected prop', () => { mountComponent({ ...defaultProps, selected: true }); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js index eb18d5c26e5..78f27c9948b 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js @@ -2,18 +2,35 @@ import { generateToolbarItem, addCustomEventListener, removeCustomEventListener, + registerHTMLToMarkdownRenderer, addImage, getMarkdown, } from '~/vue_shared/components/rich_content_editor/services/editor_service'; +import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer'; + +jest.mock('~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer'); describe('Editor Service', () => { - const mockInstance = { - eventManager: { addEventType: jest.fn(), removeEventHandler: jest.fn(), listen: jest.fn() }, - editor: { exec: jest.fn() }, - invoke: jest.fn(), - }; - const event = 'someCustomEvent'; - const handler = jest.fn(); + let mockInstance; + let event; + let handler; + + beforeEach(() => { + mockInstance = { + eventManager: { addEventType: jest.fn(), removeEventHandler: jest.fn(), listen: jest.fn() }, + editor: { exec: jest.fn() }, + invoke: jest.fn(), + toMarkOptions: { + renderer: { + constructor: { + factory: jest.fn(), + }, + }, + }, + }; + event = 'someCustomEvent'; + handler = jest.fn(); + }); describe('generateToolbarItem', () => { const config = { @@ -74,4 +91,33 @@ describe('Editor Service', () => { expect(mockInstance.invoke).toHaveBeenCalledWith('getMarkdown'); }); }); + + describe('registerHTMLToMarkdownRenderer', () => { + let baseRenderer; + const htmlToMarkdownRenderer = {}; + const extendedRenderer = {}; + + beforeEach(() => { + baseRenderer = mockInstance.toMarkOptions.renderer; + buildHTMLToMarkdownRenderer.mockReturnValueOnce(htmlToMarkdownRenderer); + baseRenderer.constructor.factory.mockReturnValueOnce(extendedRenderer); + + registerHTMLToMarkdownRenderer(mockInstance); + }); + + it('builds a new instance of the HTML to Markdown renderer', () => { + expect(buildHTMLToMarkdownRenderer).toHaveBeenCalledWith(baseRenderer); + }); + + it('extends base renderer with the HTML to Markdown renderer', () => { + expect(baseRenderer.constructor.factory).toHaveBeenCalledWith( + baseRenderer, + htmlToMarkdownRenderer, + ); + }); + + it('replaces the default renderer with extended renderer', () => { + expect(mockInstance.toMarkOptions.renderer).toBe(extendedRenderer); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js index 18e768a76aa..01f20dd7299 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js @@ -13,6 +13,7 @@ import { addCustomEventListener, removeCustomEventListener, addImage, + registerHTMLToMarkdownRenderer, } from '~/vue_shared/components/rich_content_editor/services/editor_service'; jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service', () => ({ @@ -20,6 +21,7 @@ jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service', addCustomEventListener: jest.fn(), removeCustomEventListener: jest.fn(), addImage: jest.fn(), + registerHTMLToMarkdownRenderer: jest.fn(), })); describe('Rich Content Editor', () => { @@ -86,16 +88,24 @@ describe('Rich Content Editor', () => { }); describe('when editor is loaded', () => { - it('adds the CUSTOM_EVENTS.openAddImageModal custom event listener', () => { - const mockEditorApi = { eventManager: { addEventType: jest.fn(), listen: jest.fn() } }; + let mockEditorApi; + + beforeEach(() => { + mockEditorApi = { eventManager: { addEventType: jest.fn(), listen: jest.fn() } }; findEditor().vm.$emit('load', mockEditorApi); + }); + it('adds the CUSTOM_EVENTS.openAddImageModal custom event listener', () => { expect(addCustomEventListener).toHaveBeenCalledWith( mockEditorApi, CUSTOM_EVENTS.openAddImageModal, wrapper.vm.onOpenAddImageModal, ); }); + + it('registers HTML to markdown renderer', () => { + expect(registerHTMLToMarkdownRenderer).toHaveBeenCalledWith(mockEditorApi); + }); }); describe('when editor is destroyed', () => { diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js new file mode 100644 index 00000000000..3082365959a --- /dev/null +++ b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js @@ -0,0 +1,24 @@ +import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer'; + +describe('HTMLToMarkdownRenderer', () => { + let baseRenderer; + let htmlToMarkdownRenderer; + const NODE = { nodeValue: 'mock_node' }; + + beforeEach(() => { + baseRenderer = { + trim: jest.fn(input => `trimmed ${input}`), + getSpaceCollapsedText: jest.fn(input => `space collapsed ${input}`), + getSpaceControlled: jest.fn(input => `space controlled ${input}`), + }; + htmlToMarkdownRenderer = buildHTMLToMarkdownRenderer(baseRenderer); + }); + + describe('TEXT_NODE visitor', () => { + it('composes getSpaceControlled, getSpaceCollapsedText, and trim services', () => { + expect(htmlToMarkdownRenderer.TEXT_NODE(NODE)).toBe( + `space controlled trimmed space collapsed ${NODE.nodeValue}`, + ); + }); + }); +}); diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb index ae421fe847b..a109348ea19 100644 --- a/spec/services/projects/after_import_service_spec.rb +++ b/spec/services/projects/after_import_service_spec.rb @@ -72,6 +72,26 @@ RSpec.describe Projects::AfterImportService do end end + context 'when housekeeping service lease is taken' do + let(:exception) { Projects::HousekeepingService::LeaseTaken.new } + + it 'logs the error message' do + allow_next_instance_of(Projects::HousekeepingService) do |instance| + expect(instance).to receive(:execute).and_raise(exception) + end + + expect(Gitlab::Import::Logger).to receive(:info).with( + { + message: 'Project housekeeping failed', + project_full_path: project.full_path, + project_id: project.id, + 'error.message' => exception.to_s + }).and_call_original + + subject.execute + end + end + context 'when after import action throw retriable exception one time' do let(:exception) { GRPC::DeadlineExceeded.new } diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb index 854f224bb5d..4b0c7afab6d 100644 --- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb @@ -18,7 +18,7 @@ RSpec.shared_context 'GroupPolicy context' do ] end let(:read_group_permissions) { %i[read_label read_list read_milestone read_board] } - let(:reporter_permissions) { %i[admin_label read_container_image read_metrics_dashboard_annotation] } + let(:reporter_permissions) { %i[admin_label read_container_image read_metrics_dashboard_annotation read_prometheus] } let(:developer_permissions) { %i[admin_milestone create_metrics_dashboard_annotation delete_metrics_dashboard_annotation update_metrics_dashboard_annotation] } let(:maintainer_permissions) do %i[ |