Add unit tests and fix broken endpoint

This commit is contained in:
syasonik 2019-04-16 15:01:43 +08:00
parent 18183f404e
commit 3d302879f4
6 changed files with 186 additions and 20 deletions

View file

@ -158,11 +158,11 @@ class Projects::EnvironmentsController < Projects::ApplicationController
end
def metrics_dashboard
access_denied! unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
render_403 and return unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
respond_to do |format|
format.json do
dashboard = MetricsDashboardService.new.get_dashboard
dashboard = MetricsDashboardService.new(@project).get_dashboard
render json: dashboard, status: :ok
end

View file

@ -9,40 +9,68 @@ class MetricsDashboardProcessingService
end
def process
insert_persisted_metrics!
insert_metric_ids!
sort_groups!
sort_panels!
insert_project_metrics!
@dashboard.to_json
end
private
# Inserts project-specific metrics into the dashboard config.
# If there are no project-specific metrics, this will have no effect.
def insert_persisted_metrics!
@project.prometheus_metrics.each do |persisted_metric|
group = find_or_create_group(@dashboard[:panel_groups], persisted_metric)
panel = find_or_create_panel(group[:panels], persisted_metric)
find_or_create_metric(panel[:metrics], persisted_metric)
# ------- Processing Steps -----------
# For each metric in the dashboard config, attempts to find a corresponding
# database record. If found, includes the record's id in the dashboard config.
def insert_metric_ids!
for_metrics do |metric|
metric_record = common_metrics.find { |m| m.identifier == metric[:id] }
metric[:metric_id] = metric_record.id if metric_record
end
end
# For each metric in the dashboard config, attempts to find a corresponding
# persisted record. If found, includes the record id in the config.
def insert_metric_ids!
@dashboard[:panel_groups].each do |group|
group[:panels].each do |panel|
panel[:metrics].each do |metric|
metric_record = common_metrics.find {|m| m.identifier == metric[:id] }
metric[:metric_id] = metric_record.id if metric_record
end
end
# Inserts project-specific metrics into the dashboard config.
# If there are no project-specific metrics, this will have no effect.
def insert_project_metrics!
project_metrics.each do |project_metric|
group = find_or_create_group(@dashboard[:panel_groups], project_metric)
panel = find_or_create_panel(group[:panels], project_metric)
find_or_create_metric(panel[:metrics], project_metric)
end
end
# Sorts the groups in the dashboard by the :priority key
def sort_groups!
@dashboard[:panel_groups] = @dashboard[:panel_groups].sort_by { |group| group[:priority] }
end
# Sorts the panels in the dashboard by the :weight key
def sort_panels!
@dashboard[:panel_groups].each do |group|
group[:panels] = group[:panels].sort_by { |panel| panel[:weight] }
end
end
# ------- Processing Helpers -----------
def project_metrics
@project.prometheus_metrics
end
def common_metrics
@common_metrics ||= ::PrometheusMetric.common
end
def for_metrics
@dashboard[:panel_groups].each do |panel_group|
panel_group[:panels].each do |panel|
panel[:metrics].each do |metric|
yield metric
end
end
end
end
def find_or_create_group(panel_groups, metric)
target_group = panel_groups.find { |group| group[:group] == metric.group_title }

View file

@ -461,6 +461,30 @@ describe Projects::EnvironmentsController do
end
end
describe 'metrics_dashboard' do
context 'when prometheus endpoint is disabled' do
before do
stub_feature_flags(environment_metrics_use_prometheus_endpoint: false)
end
it 'responds with status code 403' do
get :metrics_dashboard, params: environment_params(format: :json)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'when prometheus endpoint is enabled' do
it 'returns a json representation of the environment dashboard' do
get :metrics_dashboard, params: environment_params(format: :json)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to include('dashboard', 'order', 'panel_groups')
expect(json_response['panel_groups']).to all( include('group', 'priority', 'panels') )
end
end
end
describe 'GET #search' do
before do
create(:environment, name: 'staging', project: project)

View file

@ -0,0 +1,36 @@
dashboard: 'Test Dashboard'
order: 1
panel_groups:
- group: Group A
priority: 10
panels:
- title: "Super Chart A1"
type: "area-chart"
y_label: "y_label"
weight: 2
metrics:
- id: metric_a1
query_range: 'query'
unit: unit
label: Legend Label
- title: "Super Chart A2"
type: "area-chart"
y_label: "y_label"
weight: 1
metrics:
- id: metric_a2
query_range: 'query'
label: Legend Label
unit: unit
- group: Group B
priority: 1
panels:
- title: "Super Chart B"
type: "area-chart"
y_label: "y_label"
weight: 1
metrics:
- id: metric_b
query_range: 'query'
unit: unit
label: Legend Label

View file

@ -0,0 +1,56 @@
require 'spec_helper'
describe MetricsDashboardProcessingService do
let(:project) { build(:project) }
let(:dashboard_yml) { YAML.load_file('spec/fixtures/services/metrics_dashboard_processing_service.yml') }
describe 'process' do
let(:dashboard) { JSON.parse(described_class.new(dashboard_yml, project).process, symbolize_names: true) }
context 'when dashboard config corresponds to common metrics' do
let!(:common_metric) { create(:prometheus_metric, :common, identifier: 'metric_a1') }
it 'inserts metric ids into the config' do
target_metric = all_metrics.find { |metric| metric[:id] == 'metric_a1' }
expect(target_metric).to include(:metric_id)
end
end
context 'when the project has associated metrics' do
let!(:project_metric) { create(:prometheus_metric, project: project) }
it 'includes project-specific metrics' do
project_metric_details = {
query_range: project_metric.query,
unit: project_metric.unit,
label: project_metric.legend,
metric_id: project_metric.id,
}
expect(all_metrics).to include project_metric_details
end
it 'includes project metrics at the end of the config' do
expected_metrics_order = ['metric_b', 'metric_a2', 'metric_a1', nil]
actual_metrics_order = all_metrics.map { |m| m[:id] }
expect(actual_metrics_order).to eq expected_metrics_order
end
end
it 'orders groups by priority and panels by weight' do
expected_metrics_order = ['metric_b', 'metric_a2', 'metric_a1']
actual_metrics_order = all_metrics.map { |m| m[:id] }
expect(actual_metrics_order).to eq expected_metrics_order
end
end
def all_metrics
dashboard[:panel_groups].map do |group|
group[:panels].map { |panel| panel[:metrics] }
end.flatten
end
end

View file

@ -0,0 +1,22 @@
require 'spec_helper'
describe MetricsDashboardService, :use_clean_rails_memory_store_caching do
let(:project) { build(:project) }
describe 'get_dashboard' do
it 'returns a json representation of the environment dashboard' do
dashboard = described_class.new(project).get_dashboard
json = JSON.parse(dashboard, symbolize_names: true)
expect(json).to include(:dashboard, :order, :panel_groups)
expect(json[:panel_groups]).to all( include(:group, :priority, :panels) )
end
it 'caches the dashboard for subsequent calls' do
expect(YAML).to receive(:load_file).once.and_call_original
described_class.new(project).get_dashboard
described_class.new(project).get_dashboard
end
end
end