diff options
Diffstat (limited to 'spec/services/metrics')
18 files changed, 0 insertions, 2109 deletions
diff --git a/spec/services/metrics/dashboard/annotations/create_service_spec.rb b/spec/services/metrics/dashboard/annotations/create_service_spec.rb deleted file mode 100644 index 2bcfa54ead7..00000000000 --- a/spec/services/metrics/dashboard/annotations/create_service_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::Annotations::CreateService, feature_category: :metrics do - let_it_be(:user) { create(:user) } - - let(:description) { 'test annotation' } - let(:dashboard_path) { 'config/prometheus/common_metrics.yml' } - let(:starting_at) { 15.minutes.ago } - let(:ending_at) { nil } - let(:service_instance) { described_class.new(user, annotation_params) } - let(:annotation_params) do - { - environment: environment, - cluster: cluster, - description: description, - dashboard_path: dashboard_path, - starting_at: starting_at, - ending_at: ending_at - } - end - - shared_examples 'executed annotation creation' do - it 'returns success response', :aggregate_failures do - annotation = instance_double(::Metrics::Dashboard::Annotation) - allow(::Metrics::Dashboard::Annotation).to receive(:new).and_return(annotation) - allow(annotation).to receive(:save).and_return(true) - - response = service_instance.execute - - expect(response[:status]).to be :success - expect(response[:annotation]).to be annotation - end - - it 'creates annotation', :aggregate_failures do - annotation = instance_double(::Metrics::Dashboard::Annotation) - - expect(::Metrics::Dashboard::Annotation) - .to receive(:new).with(annotation_params).and_return(annotation) - expect(annotation).to receive(:save).and_return(true) - - service_instance.execute - end - end - - shared_examples 'prevented annotation creation' do |message| - it 'returns error response', :aggregate_failures do - response = service_instance.execute - - expect(response[:status]).to be :error - expect(response[:message]).to eql message - end - - it 'does not change db state' do - expect(::Metrics::Dashboard::Annotation).not_to receive(:new) - - service_instance.execute - end - end - - shared_examples 'annotation creation failure' do - it 'returns error response', :aggregate_failures do - annotation = instance_double(::Metrics::Dashboard::Annotation) - - expect(annotation).to receive(:errors).and_return('Model validation error') - expect(::Metrics::Dashboard::Annotation) - .to receive(:new).with(annotation_params).and_return(annotation) - expect(annotation).to receive(:save).and_return(false) - - response = service_instance.execute - - expect(response[:status]).to be :error - expect(response[:message]).to eql 'Model validation error' - end - end - - describe '.execute' do - context 'with environment' do - let(:environment) { create(:environment) } - let(:cluster) { nil } - - context 'with anonymous user' do - it_behaves_like 'prevented annotation creation', 'You are not authorized to create annotation for selected environment' - end - - context 'with maintainer user' do - before do - environment.project.add_maintainer(user) - end - - it_behaves_like 'executed annotation creation' - end - end - - context 'with cluster' do - let(:environment) { nil } - - context 'with anonymous user' do - let(:cluster) { create(:cluster, :project) } - - it_behaves_like 'prevented annotation creation', 'You are not authorized to create annotation for selected cluster' - end - - context 'with maintainer user' do - let(:cluster) { create(:cluster, :project) } - - before do - cluster.project.add_maintainer(user) - end - - it_behaves_like 'executed annotation creation' - end - - context 'with owner user' do - let(:cluster) { create(:cluster, :group) } - - before do - cluster.group.add_owner(user) - end - - it_behaves_like 'executed annotation creation' - end - end - - context 'non cluster nor environment is supplied' do - let(:environment) { nil } - let(:cluster) { nil } - - it_behaves_like 'annotation creation failure' - end - - context 'missing dashboard_path' do - let(:cluster) { create(:cluster, :project) } - let(:environment) { nil } - let(:dashboard_path) { nil } - - context 'with maintainer user' do - before do - cluster.project.add_maintainer(user) - end - - it_behaves_like 'annotation creation failure' - end - end - - context 'incorrect dashboard_path' do - let(:cluster) { create(:cluster, :project) } - let(:environment) { nil } - let(:dashboard_path) { 'something_incorrect.yml' } - - context 'with maintainer user' do - before do - cluster.project.add_maintainer(user) - end - - it_behaves_like 'prevented annotation creation', 'Dashboard with requested path can not be found' - end - end - end -end diff --git a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb b/spec/services/metrics/dashboard/annotations/delete_service_spec.rb deleted file mode 100644 index 557d6d95767..00000000000 --- a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::Annotations::DeleteService, feature_category: :metrics do - let(:user) { create(:user) } - let(:service_instance) { described_class.new(user, annotation) } - - shared_examples 'executed annotation deletion' do - it 'returns success response', :aggregate_failures do - expect(annotation).to receive(:destroy).and_return(true) - - response = service_instance.execute - - expect(response[:status]).to be :success - end - end - - shared_examples 'prevented annotation deletion' do |message| - it 'returns error response', :aggregate_failures do - response = service_instance.execute - - expect(response[:status]).to be :error - expect(response[:message]).to eql message - end - - it 'does not change db state' do - expect(annotation).not_to receive(:destroy) - - service_instance.execute - end - end - - describe '.execute' do - context 'with specific environment' do - let(:annotation) { create(:metrics_dashboard_annotation, environment: environment) } - let(:environment) { create(:environment) } - - context 'with anonymous user' do - it_behaves_like 'prevented annotation deletion', 'You are not authorized to delete this annotation' - end - - context 'with maintainer user' do - before do - environment.project.add_maintainer(user) - end - - it_behaves_like 'executed annotation deletion' - - context 'annotation failed to delete' do - it 'returns error response', :aggregate_failures do - allow(annotation).to receive(:destroy).and_return(false) - - response = service_instance.execute - - expect(response[:status]).to be :error - expect(response[:message]).to eql 'Annotation has not been deleted' - end - end - end - end - - context 'with specific cluster' do - let(:annotation) { create(:metrics_dashboard_annotation, cluster: cluster, environment: nil) } - - context 'with anonymous user' do - let(:cluster) { create(:cluster, :project) } - - it_behaves_like 'prevented annotation deletion', 'You are not authorized to delete this annotation' - end - - context 'with maintainer user' do - let(:cluster) { create(:cluster, :project) } - - before do - cluster.project.add_maintainer(user) - end - - it_behaves_like 'executed annotation deletion' - end - - context 'with owner user' do - let(:cluster) { create(:cluster, :group) } - - before do - cluster.group.add_owner(user) - end - - it_behaves_like 'executed annotation deletion' - end - end - end -end diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb deleted file mode 100644 index bb11b905a7c..00000000000 --- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb +++ /dev/null @@ -1,195 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching, feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :repository) } - let_it_be(:environment) { create(:environment, project: project) } - - describe '#execute' do - subject(:service_call) { described_class.new(project, user, params).execute } - - let(:commit_message) { 'test' } - let(:branch) { "dashboard_new_branch" } - let(:dashboard) { 'config/prometheus/common_metrics.yml' } - let(:file_name) { 'custom_dashboard.yml' } - let(:file_content_hash) { YAML.safe_load(File.read(dashboard)) } - let(:params) do - { - dashboard: dashboard, - file_name: file_name, - commit_message: commit_message, - branch: branch - } - end - - context 'user does not have push right to repository' do - it_behaves_like 'misconfigured dashboard service response with stepable', :forbidden, 'You are not allowed to push into this branch. Create another branch or open a merge request.' - end - - context 'with rights to push to the repository' do - before do - project.add_maintainer(user) - end - - context 'wrong target file extension' do - let(:file_name) { 'custom_dashboard.txt' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'The file name should have a .yml extension' - end - - context 'wrong source dashboard file' do - let(:dashboard) { 'config/prometheus/common_metrics_123.yml' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :not_found, 'Not found.' - end - - context 'path traversal attack attempt' do - let(:dashboard) { 'config/prometheus/../database.yml' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :not_found, 'Not found.' - end - - context 'path traversal attack attempt on target file' do - let(:file_name) { '../../custom_dashboard.yml' } - let(:dashboard_attrs) do - { - commit_message: commit_message, - branch_name: branch, - start_branch: project.default_branch, - encoding: 'text', - file_path: ".gitlab/dashboards/custom_dashboard.yml", - file_content: file_content_hash.to_yaml - } - end - - it 'strips target file name to safe value', :aggregate_failures do - allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash)) - service_instance = instance_double(::Files::CreateService) - expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance) - expect(service_instance).to receive(:execute).and_return(status: :success) - - service_call - end - end - - context 'valid parameters' do - before do - allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash)) - end - - it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH, - [ - ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, - ::Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter - ] - - it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH, - [ - ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter - ] - - context 'selected branch already exists' do - let(:branch) { 'existing_branch' } - - before do - project.repository.add_branch(user, branch, 'master') - end - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'There was an error creating the dashboard, branch named: existing_branch already exists.' - - # temporary not available function for first iteration - # follow up issue https://gitlab.com/gitlab-org/gitlab/issues/196237 which - # require this feature - # it 'pass correct params to Files::CreateService', :aggregate_failures do - # project.repository.add_branch(user, branch, 'master') - # - # service_instance = instance_double(::Files::CreateService) - # expect(::Files::CreateService).to receive(:new).with(project, user, dashboard_attrs).and_return(service_instance) - # expect(service_instance).to receive(:execute).and_return(status: :success) - # - # service_call - # end - end - - context 'blank branch name' do - let(:branch) { '' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'There was an error creating the dashboard, branch name is invalid.' - end - - context 'dashboard file already exists' do - let(:branch) { 'custom_dashboard' } - - before do - Files::CreateService.new( - project, - user, - commit_message: 'Create custom dashboard custom_dashboard.yml', - branch_name: 'master', - start_branch: 'master', - file_path: ".gitlab/dashboards/custom_dashboard.yml", - file_content: File.read('config/prometheus/common_metrics.yml') - ).execute - end - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, "A file with 'custom_dashboard.yml' already exists in custom_dashboard branch" - end - - it 'extends dashboard template path to absolute url' do - allow(::Files::CreateService).to receive(:new).and_return(double(execute: { status: :success })) - - expect_file_read(Rails.root.join('config/prometheus/common_metrics.yml'), content: '') - - service_call - end - - context 'Files::CreateService success' do - before do - allow(::Files::CreateService).to receive(:new).and_return(double(execute: { status: :success })) - end - - it 'clears dashboards cache' do - expect(project.repository).to receive(:refresh_method_caches).with([:metrics_dashboard]) - - service_call - end - - it 'returns success', :aggregate_failures do - result = service_call - dashboard_details = { - path: '.gitlab/dashboards/custom_dashboard.yml', - display_name: 'custom_dashboard.yml', - default: false, - system_dashboard: false - } - - expect(result[:status]).to be :success - expect(result[:http_status]).to be :created - expect(result[:dashboard]).to match dashboard_details - end - end - - context 'Files::CreateService fails' do - before do - allow(::Files::CreateService).to receive(:new).and_return(double(execute: { status: :error })) - end - - it 'does NOT clear dashboards cache' do - expect(project.repository).not_to receive(:refresh_method_caches) - - service_call - end - - it 'returns error' do - result = service_call - expect(result[:status]).to be :error - end - end - end - end - end -end diff --git a/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb b/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb deleted file mode 100644 index 53def716de3..00000000000 --- a/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:cluster_project) { create(:cluster_project) } - let_it_be(:cluster) { cluster_project.cluster } - let_it_be(:project) { cluster_project.project } - - before do - project.add_maintainer(user) - end - - describe '.valid_params?' do - let(:params) { { cluster: cluster, embedded: 'false' } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'with matching dashboard_path' do - let(:params) { { dashboard_path: ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH } } - - it { is_expected.to be_truthy } - end - - context 'missing cluster without dashboard_path' do - let(:params) { {} } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_params) { [project, user, { cluster: cluster, cluster_type: :admin }] } - let(:service_call) { subject.get_dashboard } - - subject { described_class.new(*service_params) } - - it_behaves_like 'valid dashboard service response' - it_behaves_like 'caches the unprocessed dashboard for subsequent calls' - it_behaves_like 'refreshes cache when dashboard_version is changed' - - it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do - let(:dashboard_path) { described_class::DASHBOARD_PATH } - let(:dashboard_version) { subject.send(:dashboard_version) } - end - - context 'when called with a non-system dashboard' do - let(:dashboard_path) { 'garbage/dashboard/path' } - - # We want to always return the cluster dashboard. - it_behaves_like 'valid dashboard service response' - end - end -end diff --git a/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb b/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb deleted file mode 100644 index 5d63505e5cc..00000000000 --- a/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::ClusterMetricsEmbedService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - using RSpec::Parameterized::TableSyntax - - let_it_be(:user) { create(:user) } - let_it_be(:cluster_project) { create(:cluster_project) } - let_it_be(:cluster) { cluster_project.cluster } - let_it_be(:project) { cluster_project.project } - - before do - project.add_maintainer(user) - end - - describe '.valid_params?' do - let(:valid_params) { { cluster: 1, embedded: 'true', group: 'hello', title: 'world', y_label: 'countries' } } - - subject { described_class } - - it { expect(subject.valid_params?(valid_params)).to be_truthy } - - context 'missing all params' do - let(:params) { {} } - - it { expect(subject.valid_params?(params)).to be_falsy } - end - - [:cluster, :embedded, :group, :title, :y_label].each do |param_key| - it 'returns false with missing param' do - params = valid_params.except(param_key) - - expect(subject.valid_params?(params)).to be_falsy - end - end - end - - describe '#get_dashboard' do - let(:service_params) do - [ - project, - user, - { - cluster: cluster, - cluster_type: :project, - embedded: 'true', - group: 'Cluster Health', - title: 'CPU Usage', - y_label: 'CPU (cores)' - } - ] - end - - let(:service_call) { described_class.new(*service_params).get_dashboard } - let(:panel_groups) { service_call[:dashboard][:panel_groups] } - let(:panel) { panel_groups.first[:panels].first } - - it_behaves_like 'valid embedded dashboard service response' - it_behaves_like 'caches the unprocessed dashboard for subsequent calls' - - it 'returns one panel' do - expect(panel_groups.size).to eq 1 - expect(panel_groups.first[:panels].size).to eq 1 - end - - it 'returns panel by title and y_label' do - expect(panel[:title]).to eq(service_params.last[:title]) - expect(panel[:y_label]).to eq(service_params.last[:y_label]) - end - end -end diff --git a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb deleted file mode 100644 index 940daa38ae7..00000000000 --- a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - let_it_be(:environment) { create(:environment, project: project) } - - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } - - subject { described_class.new(*service_params) } - - before do - project.add_maintainer(user) if user - end - - describe '#raw_dashboard' do - let(:project) { project_with_dashboard(dashboard_path) } - - it_behaves_like '#raw_dashboard raises error if dashboard loading fails' - end - - describe '#get_dashboard' do - let(:service_call) { subject.get_dashboard } - - context 'when the dashboard does not exist' do - it_behaves_like 'misconfigured dashboard service response', :not_found - - it 'does not update gitlab_metrics_dashboard_processing_time_ms metric', :prometheus do - service_call - metric = subject.send(:processing_time_metric) - labels = subject.send(:processing_time_metric_labels) - - expect(metric.get(labels)).to eq(0) - end - end - - it_behaves_like 'raises error for users with insufficient permissions' - - context 'when the dashboard exists' do - let(:project) { project_with_dashboard(dashboard_path) } - - it_behaves_like 'valid dashboard service response' - it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' - - it 'caches the unprocessed dashboard for subsequent calls' do - expect_any_instance_of(described_class) - .to receive(:get_raw_dashboard) - .once - .and_call_original - - described_class.new(*service_params).get_dashboard - described_class.new(*service_params).get_dashboard - end - - it 'tracks panel type' do - allow(::Gitlab::Tracking).to receive(:event).and_call_original - - described_class.new(*service_params).get_dashboard - - expect(::Gitlab::Tracking).to have_received(:event) - .with('MetricsDashboard::Chart', 'chart_rendered', { label: 'area-chart' }) - .at_least(:once) - end - - context 'with metric in database' do - let!(:prometheus_metric) do - create(:prometheus_metric, project: project, identifier: 'metric_a1', group: 'custom') - end - - it 'includes metric_id' do - dashboard = described_class.new(*service_params).get_dashboard - - metric_id = dashboard[:dashboard][:panel_groups].find { |panel_group| panel_group[:group] == 'Group A' } - .fetch(:panels).find { |panel| panel[:title] == 'Super Chart A1' } - .fetch(:metrics).find { |metric| metric[:id] == 'metric_a1' } - .fetch(:metric_id) - - expect(metric_id).to eq(prometheus_metric.id) - end - end - - context 'and the dashboard is then deleted' do - it 'does not return the previously cached dashboard' do - described_class.new(*service_params).get_dashboard - - delete_project_dashboard(project, user, dashboard_path) - - expect_any_instance_of(described_class) - .to receive(:get_raw_dashboard) - .once - .and_call_original - - described_class.new(*service_params).get_dashboard - end - end - end - - context 'when the dashboard is configured incorrectly' do - let(:project) { project_with_dashboard(dashboard_path, {}) } - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - end - - describe '.all_dashboard_paths' do - let(:all_dashboards) { described_class.all_dashboard_paths(project) } - - context 'when there are no project dashboards' do - it 'returns an empty array' do - expect(all_dashboards).to be_empty - end - end - - context 'when there are project dashboards available' do - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - let(:project) { project_with_dashboard(dashboard_path) } - - it 'returns the dashboard attributes' do - expect(all_dashboards).to eq( - [{ - path: dashboard_path, - display_name: 'test.yml', - default: false, - system_dashboard: false, - out_of_the_box_dashboard: false - }] - ) - end - - it 'caches repo file list' do - expect(Gitlab::Metrics::Dashboard::RepoDashboardFinder).to receive(:list_dashboards) - .with(project) - .once - .and_call_original - - described_class.all_dashboard_paths(project) - described_class.all_dashboard_paths(project) - end - end - end - - describe '.valid_params?' do - let(:params) { { dashboard_path: '.gitlab/dashboard/test.yml' } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'missing dashboard_path' do - let(:params) { {} } - - it { is_expected.to be_falsey } - end - - context 'empty dashboard_path' do - let(:params) { { dashboard_path: '' } } - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb deleted file mode 100644 index 8117296b048..00000000000 --- a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb +++ /dev/null @@ -1,147 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::CustomMetricEmbedService, feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:project, reload: true) { build(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:environment) { create(:environment, project: project) } - - before do - project.add_maintainer(user) if user - end - - let(:dashboard_path) { system_dashboard_path } - let(:group) { business_metric_title } - let(:title) { 'title' } - let(:y_label) { 'y_label' } - - describe '.valid_params?' do - let(:valid_params) do - { - embedded: true, - dashboard_path: dashboard_path, - group: group, - title: title, - y_label: y_label - } - end - - subject { described_class.valid_params?(params) } - - let(:params) { valid_params } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { valid_params.except(:embedded) } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { valid_params.merge(embedded: 'false') } - - it { is_expected.to be_falsey } - end - - context 'non-system dashboard' do - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - - it { is_expected.to be_falsey } - end - - context 'undefined dashboard' do - let(:params) { valid_params.except(:dashboard_path) } - - it { is_expected.to be_truthy } - end - - context 'non-custom metric group' do - let(:group) { 'Different Group' } - - it { is_expected.to be_falsey } - end - - context 'missing group' do - let(:group) { nil } - - it { is_expected.to be_falsey } - end - - context 'missing title' do - let(:title) { nil } - - it { is_expected.to be_falsey } - end - - context 'undefined y-axis label' do - let(:params) { valid_params.except(:y_label) } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_params) do - [ - project, - user, - { - embedded: true, - environment: environment, - dashboard_path: dashboard_path, - group: group, - title: title, - y_label: y_label - } - ] - end - - let(:service_call) { described_class.new(*service_params).get_dashboard } - - it_behaves_like 'misconfigured dashboard service response', :not_found - it_behaves_like 'raises error for users with insufficient permissions' - - context 'the custom metric exists' do - let!(:metric) { create(:prometheus_metric, project: project) } - - it_behaves_like 'valid embedded dashboard service response' - - it 'does not cache the unprocessed dashboard' do - # Fail spec if any method of Cache class is called. - stub_const('Gitlab::Metrics::Dashboard::Cache', double) - - described_class.new(*service_params).get_dashboard - end - - context 'multiple metrics meet criteria' do - let!(:metric_2) { create(:prometheus_metric, project: project, query: 'avg(metric_2)') } - - it_behaves_like 'valid embedded dashboard service response' - - it 'includes both metrics in a single panel' do - result = service_call - - panel_groups = result[:dashboard][:panel_groups] - panels = panel_groups[0][:panels] - metrics = panels[0][:metrics] - queries = metrics.map { |metric| metric[:query_range] } - - expect(panel_groups.length).to eq(1) - expect(panels.length).to eq(1) - expect(metrics.length).to eq(2) - expect(queries).to include('avg(metric_2)', 'avg(metric)') - end - end - end - - context 'when the metric exists in another project' do - let!(:metric) { create(:prometheus_metric, project: create(:project)) } - - it_behaves_like 'misconfigured dashboard service response', :not_found - end - end -end diff --git a/spec/services/metrics/dashboard/default_embed_service_spec.rb b/spec/services/metrics/dashboard/default_embed_service_spec.rb deleted file mode 100644 index 6ef248f6b09..00000000000 --- a/spec/services/metrics/dashboard/default_embed_service_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:project) { build(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:environment) { create(:environment, project: project) } - - before do - project.add_maintainer(user) if user - end - - describe '.valid_params?' do - let(:params) { { embedded: true } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { {} } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { { embedded: 'false' } } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_params) { [project, user, { environment: environment }] } - let(:service_call) { described_class.new(*service_params).get_dashboard } - - it_behaves_like 'valid embedded dashboard service response' - it_behaves_like 'raises error for users with insufficient permissions' - - it 'caches the unprocessed dashboard for subsequent calls' do - system_service = Metrics::Dashboard::SystemDashboardService - - expect(system_service).to receive(:new).once.and_call_original - - described_class.new(*service_params).get_dashboard - described_class.new(*service_params).get_dashboard - end - - context 'when called with a non-system dashboard' do - let(:dashboard_path) { 'garbage/dashboard/path' } - - it_behaves_like 'valid embedded dashboard service response' - end - end -end diff --git a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb deleted file mode 100644 index 1643f552a70..00000000000 --- a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:project) { build(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:environment) { create(:environment, project: project) } - - before do - project.add_maintainer(user) if user - end - - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - let(:group) { 'Group A' } - let(:title) { 'Super Chart A1' } - let(:y_label) { 'y_label' } - - describe '.valid_params?' do - let(:valid_params) do - { - embedded: true, - dashboard_path: dashboard_path, - group: group, - title: title, - y_label: y_label - } - end - - subject { described_class.valid_params?(params) } - - let(:params) { valid_params } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { valid_params.except(:embedded) } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { valid_params.merge(embedded: 'false') } - - it { is_expected.to be_falsey } - end - - context 'undefined dashboard' do - let(:params) { valid_params.except(:dashboard_path) } - - it { is_expected.to be_truthy } - end - - context 'missing dashboard' do - let(:dashboard) { '' } - - it { is_expected.to be_truthy } - end - - context 'missing group' do - let(:group) { '' } - - it { is_expected.to be_falsey } - end - - context 'missing title' do - let(:title) { '' } - - it { is_expected.to be_falsey } - end - - context 'undefined y-axis label' do - let(:params) { valid_params.except(:y_label) } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_params) do - [ - project, - user, - { - environment: environment, - dashboard_path: dashboard_path, - group: group, - title: title, - y_label: y_label - } - ] - end - - let(:service_call) { described_class.new(*service_params).get_dashboard } - - context 'when the dashboard does not exist' do - it_behaves_like 'misconfigured dashboard service response', :not_found - end - - context 'when the dashboard is exists' do - let(:project) { project_with_dashboard(dashboard_path) } - - it_behaves_like 'valid embedded dashboard service response' - it_behaves_like 'raises error for users with insufficient permissions' - - it 'caches the unprocessed dashboard for subsequent calls' do - expect(YAML).to receive(:safe_load).once.and_call_original - - described_class.new(*service_params).get_dashboard - described_class.new(*service_params).get_dashboard - end - - context 'when the specified group is not present on the dashboard' do - let(:group) { 'Group Not Found' } - - it_behaves_like 'misconfigured dashboard service response', :not_found - end - - context 'when the specified title is not present on the dashboard' do - let(:title) { 'Title Not Found' } - - it_behaves_like 'misconfigured dashboard service response', :not_found - end - - context 'when the specified y-axis label is not present on the dashboard' do - let(:y_label) { 'Y-Axis Not Found' } - - it_behaves_like 'misconfigured dashboard service response', :not_found - end - end - - shared_examples 'uses system dashboard' do - it 'uses the overview dashboard' do - expect(Gitlab::Metrics::Dashboard::Finder) - .to receive(:find_raw) - .with(project, dashboard_path: system_dashboard_path) - .once - - service_call - end - end - - context 'when the dashboard is nil' do - let(:dashboard_path) { nil } - - it_behaves_like 'uses system dashboard' - end - - context 'when the dashboard is not present' do - let(:dashboard_path) { '' } - - it_behaves_like 'uses system dashboard' - end - end -end diff --git a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb b/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb deleted file mode 100644 index 25812a492b2..00000000000 --- a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::GitlabAlertEmbedService, feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:alert) { create(:prometheus_alert) } - let_it_be(:project) { alert.project } - let_it_be(:user) { create(:user) } - - let(:alert_id) { alert.id } - - before_all do - project.add_maintainer(user) - end - - describe '.valid_params?' do - let(:valid_params) do - { - embedded: true, - prometheus_alert_id: alert_id - } - end - - subject { described_class.valid_params?(params) } - - let(:params) { valid_params } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { valid_params.except(:embedded) } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { valid_params.merge(embedded: 'false') } - - it { is_expected.to be_falsey } - end - - context 'missing alert id' do - let(:params) { valid_params.except(:prometheus_alert_id) } - - it { is_expected.to be_falsey } - end - - context 'missing alert id' do - let(:params) { valid_params.merge(prometheus_alert_id: 'none') } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_params) do - [ - project, - user, - { - embedded: true, - prometheus_alert_id: alert_id - } - ] - end - - let(:service_call) { described_class.new(*service_params).get_dashboard } - - context 'when alerting is available' do - it_behaves_like 'valid embedded dashboard service response' - it_behaves_like 'raises error for users with insufficient permissions' - - it 'generates an panel based on the alert' do - result = service_call - panel = result[:dashboard][:panel_groups][0][:panels][0] - metric = panel[:metrics].first - - expect(panel[:metrics].length).to eq 1 - expect(panel).to include( - title: alert.prometheus_metric.title, - y_label: alert.prometheus_metric.y_label, - type: 'area-chart' - ) - expect(metric[:metric_id]).to eq alert.prometheus_metric_id - end - - context 'when the metric does not exist' do - let(:alert_id) { -4 } - - it_behaves_like 'misconfigured dashboard service response', :not_found - end - - it 'does not cache the unprocessed dashboard' do - # Fail spec if any method of Cache class is called. - stub_const('Gitlab::Metrics::Dashboard::Cache', double) - - described_class.new(*service_params).get_dashboard - end - end - end -end diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb deleted file mode 100644 index 877a455ea44..00000000000 --- a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb +++ /dev/null @@ -1,279 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService, feature_category: :metrics do - include MetricsDashboardHelpers - include ReactiveCachingHelpers - include GrafanaApiHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:grafana_integration) { create(:grafana_integration, project: project) } - - let(:grafana_url) do - valid_grafana_dashboard_link(grafana_integration.grafana_url) - end - - before_all do - project.add_maintainer(user) - end - - describe '.valid_params?' do - let(:valid_params) { { embedded: true, grafana_url: grafana_url } } - - subject { described_class.valid_params?(params) } - - let(:params) { valid_params } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { valid_params.except(:embedded) } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { valid_params.merge(embedded: 'false') } - - it { is_expected.to be_falsey } - end - - context 'undefined grafana_url' do - let(:params) { valid_params.except(:grafana_url) } - - it { is_expected.to be_falsey } - end - end - - describe '.from_cache' do - let(:params) { [project.id, user.id, grafana_url] } - - subject { described_class.from_cache(*params) } - - it 'initializes an instance of GrafanaMetricEmbedService' do - expect(subject).to be_an_instance_of(described_class) - expect(subject.project).to eq(project) - expect(subject.current_user).to eq(user) - expect(subject.params[:grafana_url]).to eq(grafana_url) - end - - context 'with unknown users' do - let(:params) { [project.id, current_user_id, grafana_url] } - - context 'when anonymous' do - where(:current_user_id) do - [nil, ''] - end - - with_them do - it 'sets current_user as nil' do - expect(subject.current_user).to be_nil - end - end - end - - context 'when invalid' do - let(:current_user_id) { non_existing_record_id } - - it 'raise record not found error' do - expect { subject } - .to raise_error(ActiveRecord::RecordNotFound, /Couldn't find User/) - end - end - end - end - - describe '#get_dashboard', :use_clean_rails_memory_store_caching do - let(:service_params) do - [ - project, - user, - { - embedded: true, - grafana_url: grafana_url - } - ] - end - - let(:service) { described_class.new(*service_params) } - let(:service_call) { service.get_dashboard } - - context 'without caching' do - before do - synchronous_reactive_cache(service) - end - - it_behaves_like 'raises error for users with insufficient permissions' - - context 'without a grafana integration' do - before do - allow(project).to receive(:grafana_integration).and_return(nil) - end - - it_behaves_like 'misconfigured dashboard service response', :bad_request - end - - context 'when grafana cannot be reached' do - before do - allow(grafana_integration.client).to receive(:get_dashboard).and_raise(::Grafana::Client::Error) - end - - it_behaves_like 'misconfigured dashboard service response', :service_unavailable - end - - context 'when panelId is missing' do - let(:grafana_url) do - grafana_integration.grafana_url + - '/d/XDaNK6amz/gitlab-omnibus-redis' \ - '?from=1570397739557&to=1570484139557' - end - - before do - stub_dashboard_request(grafana_integration.grafana_url) - end - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - - context 'when uid is missing' do - let(:grafana_url) { grafana_integration.grafana_url + '/d/' } - - before do - stub_dashboard_request(grafana_integration.grafana_url) - end - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - - context 'when the dashboard response contains misconfigured json' do - before do - stub_dashboard_request(grafana_integration.grafana_url, body: '') - end - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - - context 'when the datasource response contains misconfigured json' do - before do - stub_dashboard_request(grafana_integration.grafana_url) - stub_datasource_request(grafana_integration.grafana_url, body: '') - end - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - - context 'when the embed was created successfully' do - before do - stub_dashboard_request(grafana_integration.grafana_url) - stub_datasource_request(grafana_integration.grafana_url) - end - - context 'when project is private and user is member' do - it_behaves_like 'valid embedded dashboard service response' - end - - context 'when project is public and user is anonymous' do - let(:project) { create(:project, :public) } - let(:user) { nil } - let(:grafana_integration) { create(:grafana_integration, project: project) } - - it_behaves_like 'valid embedded dashboard service response' - end - end - end - - context 'with caching', :use_clean_rails_memory_store_caching do - let(:cache_params) { [project.id, user.id, grafana_url] } - - context 'when value not present in cache' do - it 'returns nil' do - expect(ExternalServiceReactiveCachingWorker) - .to receive(:perform_async) - .with(service.class, service.id, *cache_params) - - expect(service_call).to eq(nil) - end - end - - context 'when value present in cache' do - let(:return_value) { { 'http_status' => :ok, 'dashboard' => '{}' } } - - before do - stub_reactive_cache(service, return_value, cache_params) - end - - it 'returns cached value' do - expect(ReactiveCachingWorker) - .not_to receive(:perform_async) - .with(service.class, service.id, *cache_params) - - expect(service_call[:http_status]).to eq(return_value[:http_status]) - expect(service_call[:dashboard]).to eq(return_value[:dashboard]) - end - end - end - end -end - -RSpec.describe Metrics::Dashboard::GrafanaUidParser do - let_it_be(:grafana_integration) { create(:grafana_integration) } - let_it_be(:project) { grafana_integration.project } - - subject { described_class.new(grafana_url, project).parse } - - context 'with a Grafana-defined uid' do - let(:grafana_url) { grafana_integration.grafana_url + '/d/XDaNK6amz/?panelId=1' } - - it { is_expected.to eq 'XDaNK6amz' } - end - - context 'with a user-defined uid' do - let(:grafana_url) { grafana_integration.grafana_url + '/d/pgbouncer-main/pgbouncer-overview?panelId=1' } - - it { is_expected.to eq 'pgbouncer-main' } - end - - context 'when a uid is not present' do - let(:grafana_url) { grafana_integration.grafana_url } - - it { is_expected.to be nil } - end - - context 'when the url starts with unrelated content' do - let(:grafana_url) { 'js:' + grafana_integration.grafana_url } - - it { is_expected.to be nil } - end -end - -RSpec.describe Metrics::Dashboard::DatasourceNameParser do - include GrafanaApiHelpers - - let(:grafana_url) { valid_grafana_dashboard_link('https://gitlab.grafana.net') } - let(:grafana_dashboard) { Gitlab::Json.parse(fixture_file('grafana/dashboard_response.json'), symbolize_names: true) } - - subject { described_class.new(grafana_url, grafana_dashboard).parse } - - it { is_expected.to eq 'GitLab Omnibus' } - - context 'when the panelId is missing from the url' do - let(:grafana_url) { 'https:/gitlab.grafana.net/d/jbdbks/' } - - it { is_expected.to be nil } - end - - context 'when the panel is not present' do - # We're looking for panelId of 8, but only 6 is present - let(:grafana_dashboard) { { dashboard: { panels: [{ id: 6 }] } } } - - it { is_expected.to be nil } - end - - context 'when the dashboard panel does not have a datasource' do - let(:grafana_dashboard) { { dashboard: { panels: [{ id: 8 }] } } } - - it { is_expected.to be nil } - end -end diff --git a/spec/services/metrics/dashboard/panel_preview_service_spec.rb b/spec/services/metrics/dashboard/panel_preview_service_spec.rb deleted file mode 100644 index 584be717d7c..00000000000 --- a/spec/services/metrics/dashboard/panel_preview_service_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::PanelPreviewService, feature_category: :metrics do - let_it_be(:project) { create(:project) } - let_it_be(:environment) { create(:environment, project: project) } - let_it_be(:panel_yml) do - <<~YML - --- - title: test panel - YML - end - - let_it_be(:dashboard) do - { - panel_groups: [ - { - panels: [{ 'title' => 'test panel' }] - } - ] - } - end - - describe '#execute' do - subject(:service_response) { described_class.new(project, panel_yml, environment).execute } - - context "valid panel's yaml" do - before do - allow_next_instance_of(::Gitlab::Metrics::Dashboard::Processor) do |processor| - allow(processor).to receive(:process).and_return(dashboard) - end - end - - it 'returns success service response' do - expect(service_response.success?).to be_truthy - end - - it 'returns processed panel' do - expect(service_response.payload).to eq('title' => 'test panel') - end - - it 'uses dashboard processor' do - sequence = [ - ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, - ::Gitlab::Metrics::Dashboard::Stages::MetricEndpointInserter, - ::Gitlab::Metrics::Dashboard::Stages::PanelIdsInserter, - ::Gitlab::Metrics::Dashboard::Stages::UrlValidator - ] - processor_params = [project, dashboard, sequence, environment: environment] - - expect_next_instance_of(::Gitlab::Metrics::Dashboard::Processor, *processor_params) do |processor| - expect(processor).to receive(:process).and_return(dashboard) - end - - service_response - end - end - - context "invalid panel's yaml" do - [ - Gitlab::Metrics::Dashboard::Errors::DashboardProcessingError, - Gitlab::Config::Loader::Yaml::NotHashError, - Gitlab::Config::Loader::Yaml::DataTooLargeError, - Gitlab::Config::Loader::FormatError - ].each do |error_class| - context "with #{error_class}" do - before do - allow_next_instance_of(::Gitlab::Metrics::Dashboard::Processor) do |processor| - allow(processor).to receive(:process).and_raise(error_class.new('error')) - end - end - - it 'returns error service response' do - expect(service_response.error?).to be_truthy - end - - it 'returns error message' do - expect(service_response.message).to eq('error') - end - end - end - end - end -end diff --git a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb deleted file mode 100644 index a6fcb6b4842..00000000000 --- a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching, - feature_category: :cell do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - let_it_be(:environment) { create(:environment, project: project) } - - let(:dashboard_path) { described_class::DASHBOARD_PATH } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } - - before do - project.add_maintainer(user) - end - - subject { described_class.new(*service_params) } - - describe '#raw_dashboard' do - it_behaves_like '#raw_dashboard raises error if dashboard loading fails' - end - - describe '.valid_params?' do - let(:params) { { dashboard_path: described_class::DASHBOARD_PATH } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'missing dashboard_path' do - let(:params) { {} } - - it { is_expected.to be_falsey } - end - - context 'non-matching dashboard_path' do - let(:params) { { dashboard_path: 'path/to/bunk.yml' } } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:service_call) { subject.get_dashboard } - - it_behaves_like 'valid dashboard service response' - it_behaves_like 'caches the unprocessed dashboard for subsequent calls' - it_behaves_like 'refreshes cache when dashboard_version is changed' - it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' - - it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do - let(:dashboard_version) { subject.send(:dashboard_version) } - end - end - - describe '.all_dashboard_paths' do - it 'returns the dashboard attributes' do - all_dashboards = described_class.all_dashboard_paths(project) - - expect(all_dashboards).to eq( - [{ - path: described_class::DASHBOARD_PATH, - display_name: described_class::DASHBOARD_NAME, - default: false, - system_dashboard: false, - out_of_the_box_dashboard: true - }] - ) - end - end -end diff --git a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb deleted file mode 100644 index b08b980e50e..00000000000 --- a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - let_it_be(:environment) { create(:environment, project: project) } - - let(:dashboard_path) { described_class::DASHBOARD_PATH } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } - - subject { described_class.new(*service_params) } - - before do - project.add_maintainer(user) if user - end - - describe '#raw_dashboard' do - it_behaves_like '#raw_dashboard raises error if dashboard loading fails' - end - - describe '#get_dashboard' do - let(:service_call) { subject.get_dashboard } - - it_behaves_like 'valid dashboard service response' - it_behaves_like 'raises error for users with insufficient permissions' - it_behaves_like 'caches the unprocessed dashboard for subsequent calls' - it_behaves_like 'refreshes cache when dashboard_version is changed' - it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' - - it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do - let(:dashboard_version) { subject.send(:dashboard_version) } - end - - context 'when called with a non-system dashboard' do - let(:dashboard_path) { 'garbage/dashboard/path' } - - # We want to always return the system dashboard. - it_behaves_like 'valid dashboard service response' - end - end - - describe '.all_dashboard_paths' do - it 'returns the dashboard attributes' do - all_dashboards = described_class.all_dashboard_paths(project) - - expect(all_dashboards).to eq( - [{ - path: described_class::DASHBOARD_PATH, - display_name: described_class::DASHBOARD_NAME, - default: true, - system_dashboard: true, - out_of_the_box_dashboard: true - }] - ) - end - end - - describe '.valid_params?' do - let(:params) { { dashboard_path: described_class::DASHBOARD_PATH } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'missing dashboard_path' do - let(:params) { {} } - - it { is_expected.to be_falsey } - end - - context 'non-matching dashboard_path' do - let(:params) { { dashboard_path: 'path/to/bunk.yml' } } - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/services/metrics/dashboard/transient_embed_service_spec.rb b/spec/services/metrics/dashboard/transient_embed_service_spec.rb deleted file mode 100644 index 1e3ccde6ae3..00000000000 --- a/spec/services/metrics/dashboard/transient_embed_service_spec.rb +++ /dev/null @@ -1,99 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::TransientEmbedService, :use_clean_rails_memory_store_caching, - feature_category: :metrics do - let_it_be(:project) { build(:project) } - let_it_be(:user) { create(:user) } - let_it_be(:environment) { create(:environment, project: project) } - - before do - project.add_maintainer(user) if user - end - - describe '.valid_params?' do - let(:params) { { embedded: 'true', embed_json: '{}' } } - - subject { described_class.valid_params?(params) } - - it { is_expected.to be_truthy } - - context 'missing embedded' do - let(:params) { { embed_json: '{}' } } - - it { is_expected.to be_falsey } - end - - context 'not embedded' do - let(:params) { { embedded: 'false', embed_json: '{}' } } - - it { is_expected.to be_falsey } - end - - context 'missing embed_json' do - let(:params) { { embedded: 'true' } } - - it { is_expected.to be_falsey } - end - end - - describe '#get_dashboard' do - let(:embed_json) { get_embed_json } - let(:service_params) { [project, user, { environment: environment, embedded: 'true', embed_json: embed_json }] } - let(:service_call) { described_class.new(*service_params).get_dashboard } - - it_behaves_like 'valid embedded dashboard service response' - it_behaves_like 'raises error for users with insufficient permissions' - - it 'caches the unprocessed dashboard for subsequent calls' do - expect_any_instance_of(described_class) - .to receive(:get_raw_dashboard) - .once - .and_call_original - - described_class.new(*service_params).get_dashboard - described_class.new(*service_params).get_dashboard - end - - it 'caches unique requests separately' do - alt_embed_json = get_embed_json('area-chart') - alt_service_params = [project, user, { environment: environment, embedded: 'true', embed_json: alt_embed_json }] - - embed = described_class.new(*service_params).get_dashboard - alt_embed = described_class.new(*alt_service_params).get_dashboard - - expect(embed).not_to eq(alt_embed) - expect(get_type_for_embed(embed)).to eq('line-graph') - expect(get_type_for_embed(alt_embed)).to eq('area-chart') - end - - context 'when embed_json cannot be parsed as json' do - let(:embed_json) { '' } - - it_behaves_like 'misconfigured dashboard service response', :unprocessable_entity - end - - private - - def get_embed_json(type = 'line-graph') - { - panel_groups: [{ - panels: [{ - type: type, - title: 'title', - y_label: 'y_label', - metrics: [{ - query_range: 'up', - label: 'y_label' - }] - }] - }] - }.to_json - end - - def get_type_for_embed(embed) - embed[:dashboard][:panel_groups][0][:panels][0][:type] - end - end -end diff --git a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb b/spec/services/metrics/dashboard/update_dashboard_service_spec.rb deleted file mode 100644 index 15bbe9f9364..00000000000 --- a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb +++ /dev/null @@ -1,159 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::Dashboard::UpdateDashboardService, :use_clean_rails_memory_store_caching, feature_category: :metrics do - include MetricsDashboardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :repository) } - let_it_be(:environment) { create(:environment, project: project) } - - describe '#execute' do - subject(:service_call) { described_class.new(project, user, params).execute } - - let(:commit_message) { 'test' } - let(:branch) { 'dashboard_new_branch' } - let(:dashboard) { 'config/prometheus/common_metrics.yml' } - let(:file_name) { 'custom_dashboard.yml' } - let(:file_content_hash) { YAML.safe_load(File.read(dashboard)) } - let(:params) do - { - file_name: file_name, - file_content: file_content_hash, - commit_message: commit_message, - branch: branch - } - end - - context 'user does not have push right to repository' do - it_behaves_like 'misconfigured dashboard service response with stepable', :forbidden, 'You are not allowed to push into this branch. Create another branch or open a merge request.' - end - - context 'with rights to push to the repository' do - before do - project.add_maintainer(user) - end - - context 'path traversal attack attempt' do - context 'with a yml extension' do - let(:file_name) { 'config/prometheus/../database.yml' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, "A file with this name doesn't exist" - end - - context 'without a yml extension' do - let(:file_name) { '../../..../etc/passwd' } - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'The file name should have a .yml extension' - end - end - - context 'valid parameters' do - it_behaves_like 'valid dashboard update process' - end - - context 'selected branch already exists' do - let(:branch) { 'existing_branch' } - - before do - project.repository.add_branch(user, branch, 'master') - end - - it_behaves_like 'misconfigured dashboard service response with stepable', :bad_request, 'There was an error updating the dashboard, branch named: existing_branch already exists.' - end - - context 'Files::UpdateService success' do - let(:merge_request) { project.merge_requests.last } - - before do - allow(::Files::UpdateService).to receive(:new).and_return(double(execute: { status: :success })) - end - - it 'returns success', :aggregate_failures do - dashboard_details = { - path: '.gitlab/dashboards/custom_dashboard.yml', - display_name: 'custom_dashboard.yml', - default: false, - system_dashboard: false - } - - expect(service_call[:status]).to be :success - expect(service_call[:http_status]).to be :created - expect(service_call[:dashboard]).to match dashboard_details - expect(service_call[:merge_request]).to eq(Gitlab::UrlBuilder.build(merge_request)) - end - - context 'when the merge request does not succeed' do - let(:error_message) { 'There was an error' } - - let(:merge_request) do - build(:merge_request, target_project: project, source_project: project, author: user) - end - - before do - merge_request.errors.add(:base, error_message) - allow_next_instance_of(::MergeRequests::CreateService) do |mr| - allow(mr).to receive(:execute).and_return(merge_request) - end - end - - it 'returns an appropriate message and status code', :aggregate_failures do - result = service_call - - expect(result.keys).to contain_exactly(:message, :http_status, :status, :last_step) - expect(result[:status]).to eq(:error) - expect(result[:http_status]).to eq(:bad_request) - expect(result[:message]).to eq(error_message) - end - end - - context 'with escaped characters in file name' do - let(:file_name) { "custom_dashboard%26copy.yml" } - - it 'escapes the special characters', :aggregate_failures do - dashboard_details = { - path: '.gitlab/dashboards/custom_dashboard©.yml', - display_name: 'custom_dashboard©.yml', - default: false, - system_dashboard: false - } - - expect(service_call[:status]).to be :success - expect(service_call[:http_status]).to be :created - expect(service_call[:dashboard]).to match dashboard_details - end - end - - context 'when pushing to the default branch' do - let(:branch) { 'master' } - - it 'does not create a merge request', :aggregate_failures do - dashboard_details = { - path: '.gitlab/dashboards/custom_dashboard.yml', - display_name: 'custom_dashboard.yml', - default: false, - system_dashboard: false - } - - expect(::MergeRequests::CreateService).not_to receive(:new) - expect(service_call.keys).to contain_exactly(:dashboard, :http_status, :status) - expect(service_call[:status]).to be :success - expect(service_call[:http_status]).to be :created - expect(service_call[:dashboard]).to match dashboard_details - end - end - end - - context 'Files::UpdateService fails' do - before do - allow(::Files::UpdateService).to receive(:new).and_return(double(execute: { status: :error })) - end - - it 'returns error' do - expect(service_call[:status]).to be :error - end - end - end - end -end diff --git a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb deleted file mode 100644 index e08bdca8410..00000000000 --- a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::UsersStarredDashboards::CreateService, feature_category: :metrics do - let_it_be(:user) { create(:user) } - - let(:dashboard_path) { 'config/prometheus/common_metrics.yml' } - let(:service_instance) { described_class.new(user, project, dashboard_path) } - let(:project) { create(:project) } - let(:starred_dashboard_params) do - { - user: user, - project: project, - dashboard_path: dashboard_path - } - end - - shared_examples 'prevented starred dashboard creation' do |message| - it 'returns error response', :aggregate_failures do - expect(Metrics::UsersStarredDashboard).not_to receive(:new) - - response = service_instance.execute - - expect(response.status).to be :error - expect(response.message).to eql message - end - end - - describe '.execute' do - context 'with anonymous user' do - it_behaves_like 'prevented starred dashboard creation', 'You are not authorized to add star to this dashboard' - end - - context 'with reporter user' do - before do - project.add_reporter(user) - end - - context 'incorrect dashboard_path' do - let(:dashboard_path) { 'something_incorrect.yml' } - - it_behaves_like 'prevented starred dashboard creation', 'Dashboard with requested path can not be found' - end - - context 'with valid dashboard path' do - it 'creates starred dashboard and returns success response', :aggregate_failures do - expect_next_instance_of(Metrics::UsersStarredDashboard, starred_dashboard_params) do |starred_dashboard| - expect(starred_dashboard).to receive(:save).and_return true - end - - response = service_instance.execute - - expect(response.status).to be :success - end - - context 'Metrics::UsersStarredDashboard has validation errors' do - it 'returns error response', :aggregate_failures do - expect_next_instance_of(Metrics::UsersStarredDashboard, starred_dashboard_params) do |starred_dashboard| - expect(starred_dashboard).to receive(:save).and_return(false) - expect(starred_dashboard).to receive(:errors).and_return(double(messages: { base: ['Model validation error'] })) - end - - response = service_instance.execute - - expect(response.status).to be :error - expect(response.message).to eql(base: ['Model validation error']) - end - end - end - end - end -end diff --git a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb b/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb deleted file mode 100644 index 8c4bcecc239..00000000000 --- a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Metrics::UsersStarredDashboards::DeleteService, feature_category: :metrics do - subject(:service_instance) { described_class.new(user, project, dashboard_path) } - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } - - describe '#execute' do - let_it_be(:user_starred_dashboard_1) { create(:metrics_users_starred_dashboard, user: user, project: project, dashboard_path: 'dashboard_1') } - let_it_be(:user_starred_dashboard_2) { create(:metrics_users_starred_dashboard, user: user, project: project) } - let_it_be(:other_user_starred_dashboard) { create(:metrics_users_starred_dashboard, project: project) } - let_it_be(:other_project_starred_dashboard) { create(:metrics_users_starred_dashboard, user: user) } - - context 'without dashboard_path' do - let(:dashboard_path) { nil } - - it 'does not scope user starred dashboards by dashboard path' do - result = service_instance.execute - - expect(result.success?).to be_truthy - expect(result.payload[:deleted_rows]).to be(2) - expect(Metrics::UsersStarredDashboard.all).to contain_exactly(other_user_starred_dashboard, other_project_starred_dashboard) - end - end - - context 'with dashboard_path' do - let(:dashboard_path) { 'dashboard_1' } - - it 'does scope user starred dashboards by dashboard path' do - result = service_instance.execute - - expect(result.success?).to be_truthy - expect(result.payload[:deleted_rows]).to be(1) - expect(Metrics::UsersStarredDashboard.all).to contain_exactly(user_starred_dashboard_2, other_user_starred_dashboard, other_project_starred_dashboard) - end - end - end -end |