summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb46
-rw-r--r--spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json3
-rw-r--r--spec/lib/gitlab/metrics/dashboard/defaults_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/dashboard/finder_spec.rb76
-rw-r--r--spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb80
-rw-r--r--spec/models/prometheus_metric_spec.rb13
-rw-r--r--spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb145
-rw-r--r--spec/services/metrics/dashboard/dynamic_embed_service_spec.rb151
-rw-r--r--spec/support/helpers/metrics_dashboard_helpers.rb8
9 files changed, 519 insertions, 11 deletions
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 8872e8d38e7..b3852355d77 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -518,10 +518,10 @@ describe Projects::EnvironmentsController do
end
end
- shared_examples_for 'the default dynamic dashboard' do
+ shared_examples_for 'specified dashboard embed' do |expected_titles|
it_behaves_like '200 response'
- it 'contains only the Memory and CPU charts' do
+ it 'contains only the specified charts' do
get :metrics_dashboard, params: environment_params(dashboard_params)
dashboard = json_response['dashboard']
@@ -531,10 +531,14 @@ describe Projects::EnvironmentsController do
expect(dashboard['dashboard']).to be_nil
expect(dashboard['panel_groups'].length).to eq 1
expect(panel_group['group']).to be_nil
- expect(titles).to eq ['Memory Usage (Total)', 'Core Usage (Total)']
+ expect(titles).to eq expected_titles
end
end
+ shared_examples_for 'the default dynamic dashboard' do
+ it_behaves_like 'specified dashboard embed', ['Memory Usage (Total)', 'Core Usage (Total)']
+ end
+
shared_examples_for 'dashboard can be specified' do
context 'when dashboard is specified' do
let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
@@ -551,7 +555,7 @@ describe Projects::EnvironmentsController do
end
context 'when the specified dashboard is the default dashboard' do
- let(:dashboard_path) { ::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH }
+ let(:dashboard_path) { system_dashboard_path }
it_behaves_like 'the default dashboard'
end
@@ -564,12 +568,40 @@ describe Projects::EnvironmentsController do
it_behaves_like 'the default dynamic dashboard'
- context 'when the dashboard is specified' do
- let(:dashboard_params) { { format: :json, embedded: true, dashboard: '.gitlab/dashboards/fake.yml' } }
+ context 'when incomplete dashboard params are provided' do
+ let(:dashboard_params) { { format: :json, embedded: true, title: 'Title' } }
+
+ # The title param should be ignored.
+ it_behaves_like 'the default dynamic dashboard'
+ end
+
+ context 'when invalid params are provided' do
+ let(:dashboard_params) { { format: :json, embedded: true, metric_id: 16 } }
- # The dashboard param should be ignored.
+ # The superfluous param should be ignored.
it_behaves_like 'the default dynamic dashboard'
end
+
+ context 'when the dashboard is correctly specified' do
+ let(:dashboard_params) do
+ {
+ format: :json,
+ embedded: true,
+ dashboard: system_dashboard_path,
+ group: business_metric_title,
+ title: 'title',
+ y_label: 'y_label'
+ }
+ end
+
+ it_behaves_like 'error response', :not_found
+
+ context 'and exists' do
+ let!(:metric) { create(:prometheus_metric, project: project) }
+
+ it_behaves_like 'specified dashboard embed', ['title']
+ end
+ end
end
end
diff --git a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
index 33393805464..9c1be32645a 100644
--- a/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
+++ b/spec/fixtures/lib/gitlab/metrics/dashboard/schemas/metrics.json
@@ -16,7 +16,8 @@
"unit": { "type": "string" },
"label": { "type": "string" },
"track": { "type": "string" },
- "prometheus_endpoint_path": { "type": "string" }
+ "prometheus_endpoint_path": { "type": "string" },
+ "metric_id": { "type": "number" }
},
"additionalProperties": false
}
diff --git a/spec/lib/gitlab/metrics/dashboard/defaults_spec.rb b/spec/lib/gitlab/metrics/dashboard/defaults_spec.rb
new file mode 100644
index 00000000000..420b246b3f5
--- /dev/null
+++ b/spec/lib/gitlab/metrics/dashboard/defaults_spec.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Metrics::Dashboard::Defaults do
+ it { is_expected.to be_const_defined(:DEFAULT_PANEL_TYPE) }
+ it { is_expected.to be_const_defined(:DEFAULT_PANEL_WEIGHT) }
+end
diff --git a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
index e57c7326320..ce1bb49f5c9 100644
--- a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
@@ -5,10 +5,9 @@ require 'spec_helper'
describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
- set(:project) { build(:project) }
+ set(:project) { create(:project) }
set(:user) { create(:user) }
set(:environment) { create(:environment, project: project) }
- let(:system_dashboard_path) { ::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH}
before do
project.add_maintainer(user)
@@ -52,9 +51,80 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi
end
context 'when the dashboard is expected to be embedded' do
- let(:service_call) { described_class.find(project, user, environment, dashboard_path: nil, embedded: true) }
+ let(:service_call) { described_class.find(project, user, environment, **params) }
+ let(:params) { { embedded: true } }
it_behaves_like 'valid embedded dashboard service response'
+
+ context 'when params are incomplete' do
+ let(:params) { { embedded: true, dashboard_path: system_dashboard_path } }
+
+ it_behaves_like 'valid embedded dashboard service response'
+ end
+
+ context 'when the panel is specified' do
+ context 'as a custom metric' do
+ let(:params) do
+ { embedded: true,
+ dashboard_path: system_dashboard_path,
+ group: business_metric_title,
+ title: 'title',
+ y_label: 'y_label' }
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :not_found
+
+ context 'when the metric exists' do
+ before do
+ create(:prometheus_metric, project: project)
+ end
+
+ it_behaves_like 'valid embedded dashboard service response'
+ end
+ end
+
+ context 'as a project-defined panel' do
+ let(:dashboard_path) { '.gitlab/dashboard/test.yml' }
+ let(:params) do
+ { embedded: true,
+ dashboard_path: dashboard_path,
+ group: 'Group A',
+ title: 'Super Chart A1',
+ y_label: 'y_label' }
+ end
+
+ it_behaves_like 'misconfigured dashboard service response', :not_found
+
+ context 'when the metric exists' do
+ let(:project) { project_with_dashboard(dashboard_path) }
+
+ it_behaves_like 'valid embedded dashboard service response'
+ end
+ end
+ end
+ end
+ end
+
+ describe '.find_raw' do
+ let(:dashboard) { YAML.load_file(Rails.root.join('config', 'prometheus', 'common_metrics.yml')) }
+ let(:params) { {} }
+
+ subject { described_class.find_raw(project, **params) }
+
+ it { is_expected.to eq dashboard }
+
+ context 'when the system dashboard is specified' do
+ let(:params) { { dashboard_path: system_dashboard_path } }
+
+ it { is_expected.to eq dashboard }
+ end
+
+ context 'when an existing project dashboard is specified' do
+ let(:dashboard) { YAML.safe_load(fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml')) }
+ let(:params) { { dashboard_path: '.gitlab/dashboards/test.yml' } }
+ let(:project) { project_with_dashboard(params[:dashboard_path]) }
+
+ it { is_expected.to eq dashboard }
end
end
diff --git a/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb b/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb
new file mode 100644
index 00000000000..095d0a2df78
--- /dev/null
+++ b/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Metrics::Dashboard::ServiceSelector do
+ include MetricsDashboardHelpers
+
+ describe '#call' do
+ let(:arguments) { {} }
+
+ subject { described_class.call(arguments) }
+
+ it { is_expected.to be Metrics::Dashboard::SystemDashboardService }
+
+ context 'when just the dashboard path is provided' do
+ let(:arguments) { { dashboard_path: '.gitlab/dashboards/test.yml' } }
+
+ it { is_expected.to be Metrics::Dashboard::ProjectDashboardService }
+
+ context 'when the path is for the system dashboard' do
+ let(:arguments) { { dashboard_path: system_dashboard_path } }
+
+ it { is_expected.to be Metrics::Dashboard::SystemDashboardService }
+ end
+ end
+
+ context 'when the embedded flag is provided' do
+ let(:arguments) { { embedded: true } }
+
+ it { is_expected.to be Metrics::Dashboard::DefaultEmbedService }
+
+ context 'when an incomplete set of dashboard identifiers are provided' do
+ let(:arguments) { { embedded: true, dashboard_path: '.gitlab/dashboards/test.yml' } }
+
+ it { is_expected.to be Metrics::Dashboard::DefaultEmbedService }
+ end
+
+ context 'when all the chart identifiers are provided' do
+ let(:arguments) do
+ {
+ embedded: true,
+ dashboard_path: '.gitlab/dashboards/test.yml',
+ group: 'Important Metrics',
+ title: 'Total Requests',
+ y_label: 'req/sec'
+ }
+ end
+
+ it { is_expected.to be Metrics::Dashboard::DynamicEmbedService }
+ end
+
+ context 'when all chart params expect dashboard_path are provided' do
+ let(:arguments) do
+ {
+ embedded: true,
+ group: 'Important Metrics',
+ title: 'Total Requests',
+ y_label: 'req/sec'
+ }
+ end
+
+ it { is_expected.to be Metrics::Dashboard::DynamicEmbedService }
+ end
+
+ context 'with a system dashboard and "custom" group' do
+ let(:arguments) do
+ {
+ embedded: true,
+ dashboard_path: system_dashboard_path,
+ group: business_metric_title,
+ title: 'Total Requests',
+ y_label: 'req/sec'
+ }
+ end
+
+ it { is_expected.to be Metrics::Dashboard::CustomMetricEmbedService }
+ end
+ end
+ end
+end
diff --git a/spec/models/prometheus_metric_spec.rb b/spec/models/prometheus_metric_spec.rb
index 3610408c138..a123ff5a2a6 100644
--- a/spec/models/prometheus_metric_spec.rb
+++ b/spec/models/prometheus_metric_spec.rb
@@ -150,4 +150,17 @@ describe PrometheusMetric do
expect(subject.to_query_metric.queries).to eq(queries)
end
end
+
+ describe '#to_metric_hash' do
+ it 'returns a hash suitable for inclusion on a metrics dashboard' do
+ expected_output = {
+ query_range: subject.query,
+ unit: subject.unit,
+ label: subject.legend,
+ metric_id: subject.id
+ }
+
+ expect(subject.to_metric_hash).to eq(expected_output)
+ 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
new file mode 100644
index 00000000000..53b7497ae21
--- /dev/null
+++ b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb
@@ -0,0 +1,145 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Metrics::Dashboard::CustomMetricEmbedService do
+ include MetricsDashboardHelpers
+
+ set(:project) { build(:project) }
+ set(:user) { create(:user) }
+ set(:environment) { create(:environment, project: project) }
+
+ before do
+ project.add_maintainer(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 'not embedded' do
+ let(:params) { valid_params.except(:embedded) }
+
+ 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
+ expect(Gitlab::Metrics::Dashboard::Cache).not_to receive(:fetch)
+
+ 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' do
+ result = service_call
+ included_queries = all_queries(result[:dashboard])
+
+ expect(included_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
+
+ private
+
+ def all_queries(dashboard)
+ dashboard[:panel_groups].flat_map do |group|
+ group[:panels].flat_map do |panel|
+ panel[:metrics].map do |metric|
+ metric[:query_range]
+ end
+ end
+ 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
new file mode 100644
index 00000000000..a0f7315f750
--- /dev/null
+++ b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb
@@ -0,0 +1,151 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching do
+ include MetricsDashboardHelpers
+
+ set(:project) { build(:project) }
+ set(:user) { create(:user) }
+ set(:environment) { create(:environment, project: project) }
+
+ before do
+ project.add_maintainer(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 'not embedded' do
+ let(:params) { valid_params.except(:embedded) }
+
+ 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 default 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/support/helpers/metrics_dashboard_helpers.rb b/spec/support/helpers/metrics_dashboard_helpers.rb
index 1511a2f6b49..0e86b6dfda7 100644
--- a/spec/support/helpers/metrics_dashboard_helpers.rb
+++ b/spec/support/helpers/metrics_dashboard_helpers.rb
@@ -18,6 +18,14 @@ module MetricsDashboardHelpers
project.repository.refresh_method_caches([:metrics_dashboard])
end
+ def system_dashboard_path
+ Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH
+ end
+
+ def business_metric_title
+ PrometheusMetricEnums.group_details[:business][:group_title]
+ end
+
shared_examples_for 'misconfigured dashboard service response' do |status_code|
it 'returns an appropriate message and status code' do
result = service_call