diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-19 03:09:15 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-19 03:09:15 +0300 |
commit | 60f63d15794e62c4bac9756445f618cd9acb8654 (patch) | |
tree | 30c2b2dc678995dd332b32672f9faa460fabdb79 /spec | |
parent | 93d7441cc98c1db55797a2181a3d9f4b3d26d82c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
12 files changed, 297 insertions, 111 deletions
diff --git a/spec/graphql/types/board_type_spec.rb b/spec/graphql/types/board_type_spec.rb new file mode 100644 index 00000000000..9d18065bbcd --- /dev/null +++ b/spec/graphql/types/board_type_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GitlabSchema.types['Board'] do + it { expect(described_class.graphql_name).to eq('Board') } + + it { expect(described_class).to require_graphql_authorizations(:read_board) } + + it 'has specific fields' do + expected_fields = %w[id name] + + is_expected.to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb index 6a0028f6529..240dd9fa5e2 100644 --- a/spec/graphql/types/group_type_spec.rb +++ b/spec/graphql/types/group_type_spec.rb @@ -16,9 +16,17 @@ describe GitlabSchema.types['Group'] do web_url avatar_url share_with_group_lock project_creation_level subgroup_creation_level require_two_factor_authentication two_factor_grace_period auto_devops_enabled emails_disabled - mentions_disabled parent + mentions_disabled parent boards ] is_expected.to include_graphql_fields(*expected_fields) end + + describe 'boards field' do + subject { described_class.fields['boards'] } + + it 'returns boards' do + is_expected.to have_graphql_type(Types::BoardType.connection_type) + end + end end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index ac2d2d6f7f0..9c6d1e3f35c 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -24,6 +24,7 @@ describe GitlabSchema.types['Project'] do namespace group statistics repository merge_requests merge_request issues issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments + boards ] is_expected.to include_graphql_fields(*expected_fields) @@ -77,4 +78,10 @@ describe GitlabSchema.types['Project'] do it { is_expected.to have_graphql_type(Types::EnvironmentType.connection_type) } it { is_expected.to have_graphql_resolver(Resolvers::EnvironmentsResolver) } end + + describe 'boards field' do + subject { described_class.fields['boards'] } + + it { is_expected.to have_graphql_type(Types::BoardType.connection_type) } + end end diff --git a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb index fd6f8816b63..9ac06a90efd 100644 --- a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb +++ b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb @@ -8,40 +8,26 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do let_it_be(:project) { create(:project) } let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } - let(:input) { %(<a href="#{url}">example</a>) } + let(:input) { %(<a href="#{trigger_url}">example</a>) } let(:doc) { filter(input) } - - let(:url) { grafana_integration.grafana_url + dashboard_path } let(:dashboard_path) do '/d/XDaNK6amz/gitlab-omnibus-redis' \ '?from=1570397739557&to=1570484139557' \ '&var-instance=All&panelId=14' end - it 'appends a metrics charts placeholder with dashboard url after metrics links' do - node = doc.at_css('.js-render-metrics') - expect(node).to be_present - - dashboard_url = urls.project_grafana_api_metrics_dashboard_url( + let(:trigger_url) { grafana_integration.grafana_url + dashboard_path } + let(:dashboard_url) do + urls.project_grafana_api_metrics_dashboard_url( project, embedded: true, - grafana_url: url, + grafana_url: trigger_url, start: "2019-10-06T21:35:39Z", end: "2019-10-07T21:35:39Z" ) - - expect(node.attribute('data-dashboard-url').to_s).to eq(dashboard_url) end - context 'when the dashboard link is part of a paragraph' do - let(:paragraph) { %(This is an <a href="#{url}">example</a> of metrics.) } - let(:input) { %(<p>#{paragraph}</p>) } - - it 'appends the charts placeholder after the enclosing paragraph' do - expect(unescape(doc.at_css('p').to_s)).to include(paragraph) - expect(doc.at_css('.js-render-metrics')).to be_present - end - end + it_behaves_like 'a metrics embed filter' context 'when grafana is not configured' do before do diff --git a/spec/lib/banzai/filter/inline_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_metrics_filter_spec.rb index 66bbcbf7292..1546a5e88ed 100644 --- a/spec/lib/banzai/filter/inline_metrics_filter_spec.rb +++ b/spec/lib/banzai/filter/inline_metrics_filter_spec.rb @@ -5,66 +5,31 @@ require 'spec_helper' describe Banzai::Filter::InlineMetricsFilter do include FilterSpecHelper - let(:input) { %(<a href="#{url}">example</a>) } - let(:doc) { filter(input) } - - context 'when the document has an external link' do - let(:url) { 'https://foo.com' } - - it 'leaves regular non-metrics links unchanged' do - expect(doc.to_s).to eq(input) - end - end - - context 'when the document has a metrics dashboard link' do - let(:params) { ['foo', 'bar', 12] } - let(:url) { urls.metrics_namespace_project_environment_url(*params) } - - it 'leaves the original link unchanged' do - expect(doc.at_css('a').to_s).to eq(input) - end - - it 'appends a metrics charts placeholder with dashboard url after metrics links' do - node = doc.at_css('.js-render-metrics') - expect(node).to be_present - - dashboard_url = urls.metrics_dashboard_namespace_project_environment_url(*params, embedded: true) - expect(node.attribute('data-dashboard-url').to_s).to eq(dashboard_url) + let(:params) { ['foo', 'bar', 12] } + let(:query_params) { {} } + + let(:trigger_url) { urls.metrics_namespace_project_environment_url(*params, query_params) } + let(:dashboard_url) { urls.metrics_dashboard_namespace_project_environment_url(*params, **query_params, embedded: true) } + + it_behaves_like 'a metrics embed filter' + + context 'with query params specified' do + let(:query_params) do + { + dashboard: 'config/prometheus/common_metrics.yml', + group: 'System metrics (Kubernetes)', + title: 'Core Usage (Pod Average)', + y_label: 'Cores per Pod' + } end - context 'when the metrics dashboard link is part of a paragraph' do - let(:paragraph) { %(This is an <a href="#{url}">example</a> of metrics.) } - let(:input) { %(<p>#{paragraph}</p>) } - - it 'appends the charts placeholder after the enclosing paragraph' do - expect(doc.at_css('p').to_s).to include(paragraph) - expect(doc.at_css('.js-render-metrics')).to be_present - end - end - - context 'with dashboard params specified' do - let(:params) do - [ - 'foo', - 'bar', - 12, - { - embedded: true, - dashboard: 'config/prometheus/common_metrics.yml', - group: 'System metrics (Kubernetes)', - title: 'Core Usage (Pod Average)', - y_label: 'Cores per Pod' - } - ] - end + it_behaves_like 'a metrics embed filter' + end - it 'appends a metrics charts placeholder with dashboard url after metrics links' do - node = doc.at_css('.js-render-metrics') - expect(node).to be_present + it 'leaves links to other dashboards unchanged' do + url = urls.namespace_project_grafana_api_metrics_dashboard_url('foo', 'bar') + input = %(<a href="#{url}">example</a>) - dashboard_url = urls.metrics_dashboard_namespace_project_environment_url(*params) - expect(node.attribute('data-dashboard-url').to_s).to eq(dashboard_url) - end - end + expect(filter(input).to_s).to eq(input) end end diff --git a/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb b/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb index e2615ea5069..f91927412cb 100644 --- a/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/inline_metrics_redactor_filter_spec.rb @@ -18,33 +18,6 @@ describe Banzai::Filter::InlineMetricsRedactorFilter do end context 'with a metrics charts placeholder' do - shared_examples_for 'a supported metrics dashboard url' do - context 'no user is logged in' do - it 'redacts the placeholder' do - expect(doc.to_s).to be_empty - end - end - - context 'the user does not have permission do see charts' do - let(:doc) { filter(input, current_user: build(:user)) } - - it 'redacts the placeholder' do - expect(doc.to_s).to be_empty - end - end - - context 'the user has requisite permissions' do - let(:user) { create(:user) } - let(:doc) { filter(input, current_user: user) } - - it 'leaves the placeholder' do - project.add_maintainer(user) - - expect(doc.to_s).to eq input - end - end - end - let(:input) { %(<div class="js-render-metrics" data-dashboard-url="#{url}"></div>) } it_behaves_like 'a supported metrics dashboard url' diff --git a/spec/requests/api/graphql/boards/boards_query_spec.rb b/spec/requests/api/graphql/boards/boards_query_spec.rb new file mode 100644 index 00000000000..d0a2d0fffaf --- /dev/null +++ b/spec/requests/api/graphql/boards/boards_query_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'get list of boards' do + include GraphqlHelpers + + include_context 'group and project boards query context' + + describe 'for a project' do + let(:board_parent) { create(:project, :repository, :private) } + let(:boards_data) { graphql_data['project']['boards']['edges'] } + + it_behaves_like 'group and project boards query' + end + + describe 'for a group' do + let(:board_parent) { create(:group, :private) } + let(:boards_data) { graphql_data['group']['boards']['edges'] } + + before do + allow(board_parent).to receive(:multiple_issue_boards_available?).and_return(false) + end + + it_behaves_like 'group and project boards query' + end +end diff --git a/spec/services/incident_management/create_issue_service_spec.rb b/spec/services/incident_management/create_issue_service_spec.rb index e720aafb897..4c7fb682193 100644 --- a/spec/services/incident_management/create_issue_service_spec.rb +++ b/spec/services/incident_management/create_issue_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe IncidentManagement::CreateIssueService do let(:project) { create(:project, :repository, :private) } - let(:user) { User.alert_bot } + let_it_be(:user) { User.alert_bot } let(:service) { described_class.new(project, alert_payload) } let(:alert_starts_at) { Time.now } let(:alert_title) { 'TITLE' } @@ -29,7 +29,6 @@ describe IncidentManagement::CreateIssueService do context 'when create_issue enabled' do let(:issue) { subject[:issue] } - let(:summary_separator) { "\n---\n\n" } before do setting.update!(create_issue: true) @@ -42,7 +41,7 @@ describe IncidentManagement::CreateIssueService do expect(issue.author).to eq(user) expect(issue.title).to eq(alert_title) expect(issue.description).to include(alert_presenter.issue_summary_markdown.strip) - expect(separator_count(issue.description)).to eq 0 + expect(separator_count(issue.description)).to eq(0) end end @@ -74,7 +73,7 @@ describe IncidentManagement::CreateIssueService do expect(subject).to include(status: :success) expect(issue.description).to include(alert_presenter.issue_summary_markdown) - expect(separator_count(issue.description)).to eq 1 + expect(separator_count(issue.description)).to eq(1) expect(issue.description).to include(template_content) end end @@ -134,7 +133,7 @@ describe IncidentManagement::CreateIssueService do expect(issue.description).to include(alert_presenter.issue_summary_markdown) expect(issue.description).to include(template_content) expect(issue.description).to include(alt_template) - expect(separator_count(issue.description)).to eq 2 + expect(separator_count(issue.description)).to eq(2) end end @@ -171,7 +170,7 @@ describe IncidentManagement::CreateIssueService do expect(issue.title).to include(query_title) expect(issue.title).to include('for 5 minutes') expect(issue.description).to include(alert_presenter.issue_summary_markdown.strip) - expect(separator_count(issue.description)).to eq 0 + expect(separator_count(issue.description)).to eq(0) end end @@ -306,6 +305,8 @@ describe IncidentManagement::CreateIssueService do end def separator_count(text) + summary_separator = "\n\n---\n\n" + text.scan(summary_separator).size end end diff --git a/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb b/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb new file mode 100644 index 00000000000..e744c3d0abb --- /dev/null +++ b/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +RSpec.shared_context 'group and project boards query context' do + let_it_be(:user) { create :user } + let(:current_user) { user } + let(:params) { '' } + let(:board_parent_type) { board_parent.class.to_s.downcase } + let(:start_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['startCursor'] } + let(:end_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['endCursor'] } + + def query(board_params = params) + graphql_query_for( + board_parent_type, + { 'fullPath' => board_parent.full_path }, + <<~BOARDS + boards(#{board_params}) { + pageInfo { + startCursor + endCursor + } + edges { + node { + #{all_graphql_fields_for('boards'.classify)} + } + } + } + BOARDS + ) + end + + def grab_names(data = boards_data) + data.map do |board| + board.dig('node', 'name') + end + end +end diff --git a/spec/support/shared_examples/banzai/filters/inline_embeds_shared_examples.rb b/spec/support/shared_examples/banzai/filters/inline_embeds_shared_examples.rb new file mode 100644 index 00000000000..599161abbfe --- /dev/null +++ b/spec/support/shared_examples/banzai/filters/inline_embeds_shared_examples.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Expects 2 attributes to be defined: +# trigger_url - Url expected to trigger the insertion of a placeholder. +# dashboard_url - Url expected to be present in the placeholder. +RSpec.shared_examples 'a metrics embed filter' do + let(:input) { %(<a href="#{url}">example</a>) } + let(:doc) { filter(input) } + + context 'when the document has an external link' do + let(:url) { 'https://foo.com' } + + it 'leaves regular non-metrics links unchanged' do + expect(doc.to_s).to eq(input) + end + end + + context 'when the document contains an embeddable link' do + let(:url) { trigger_url } + + it 'leaves the original link unchanged' do + expect(unescape(doc.at_css('a').to_s)).to eq(input) + end + + it 'appends a metrics charts placeholder' do + node = doc.at_css('.js-render-metrics') + expect(node).to be_present + + expect(node.attribute('data-dashboard-url').to_s).to eq(dashboard_url) + end + + context 'in a paragraph' do + let(:paragraph) { %(This is an <a href="#{url}">example</a> of metrics.) } + let(:input) { %(<p>#{paragraph}</p>) } + + it 'appends a metrics charts placeholder after the enclosing paragraph' do + expect(unescape(doc.at_css('p').to_s)).to include(paragraph) + expect(doc.at_css('.js-render-metrics')).to be_present + end + end + end + + # Nokogiri escapes the URLs, but we don't care about that + # distinction for the purposes of these filters + def unescape(html) + CGI.unescapeHTML(html) + end +end diff --git a/spec/support/shared_examples/banzai/filters/inline_metrics_redactor_shared_examples.rb b/spec/support/shared_examples/banzai/filters/inline_metrics_redactor_shared_examples.rb new file mode 100644 index 00000000000..d283b3a3b27 --- /dev/null +++ b/spec/support/shared_examples/banzai/filters/inline_metrics_redactor_shared_examples.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'a supported metrics dashboard url' do + context 'no user is logged in' do + it 'redacts the placeholder' do + expect(doc.to_s).to be_empty + end + end + + context 'the user does not have permission do see charts' do + let(:doc) { filter(input, current_user: build(:user)) } + + it 'redacts the placeholder' do + expect(doc.to_s).to be_empty + end + end + + context 'the user has requisite permissions' do + let(:user) { create(:user) } + let(:doc) { filter(input, current_user: user) } + + it 'leaves the placeholder' do + project.add_maintainer(user) + + expect(doc.to_s).to eq(input) + end + end +end diff --git a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb new file mode 100644 index 00000000000..6044fefd2f7 --- /dev/null +++ b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'group and project boards query' do + include GraphqlHelpers + + it_behaves_like 'a working graphql query' do + before do + post_graphql(query, current_user: current_user) + end + end + + context 'when the user does not have access to the board parent' do + it 'returns nil' do + create(:board, resource_parent: board_parent, name: 'A') + + post_graphql(query) + + expect(graphql_data[board_parent_type]).to be_nil + end + end + + context 'when no permission to read board' do + it 'does not return any boards' do + board_parent.add_guest(current_user) + board = create(:board, resource_parent: board_parent, name: 'A') + + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_board, board).and_return(false) + + post_graphql(query, current_user: current_user) + + expect(boards_data).to be_empty + end + end + + context 'when user can read the board parent' do + before do + board_parent.add_reporter(current_user) + end + + it 'does not create a default board' do + post_graphql(query, current_user: current_user) + + expect(boards_data).to be_empty + end + + describe 'sorting and pagination' do + context 'when using default sorting' do + let!(:board_B) { create(:board, resource_parent: board_parent, name: 'B') } + let!(:board_C) { create(:board, resource_parent: board_parent, name: 'C') } + let!(:board_a) { create(:board, resource_parent: board_parent, name: 'a') } + let!(:board_A) { create(:board, resource_parent: board_parent, name: 'A') } + + before do + post_graphql(query, current_user: current_user) + end + + it_behaves_like 'a working graphql query' + + context 'when ascending' do + let(:boards) { [board_a, board_A, board_B, board_C] } + let(:expected_boards) do + if board_parent.multiple_issue_boards_available? + boards + else + [boards.first] + end + end + + it 'sorts boards' do + expect(grab_names).to eq expected_boards.map(&:name) + end + + context 'when paginating' do + let(:params) { 'first: 2' } + + it 'sorts boards' do + expect(grab_names).to eq expected_boards.first(2).map(&:name) + + cursored_query = query("after: \"#{end_cursor}\"") + post_graphql(cursored_query, current_user: current_user) + + response_data = JSON.parse(response.body)['data'][board_parent_type]['boards']['edges'] + + expect(grab_names(response_data)).to eq expected_boards.drop(2).first(2).map(&:name) + end + end + end + end + end + end +end |