Commit d862cf00 authored by Nick Thomas's avatar Nick Thomas

Merge branch 'custom-dashboard-validation' into 'master'

Custom monitoring dashboard validation

See merge request gitlab-org/gitlab!22893
parents 36b70d9c aea00b87
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusDashboard
include ActiveModel::Model
attr_accessor :dashboard, :panel_groups
validates :dashboard, presence: true
validates :panel_groups, presence: true
def self.from_json(json_content)
dashboard = new(
dashboard: json_content['dashboard'],
panel_groups: json_content['panel_groups'].map { |group| PrometheusPanelGroup.from_json(group) }
)
dashboard.tap(&:validate!)
end
def to_yaml
self.as_json(only: valid_attributes).to_yaml
end
private
def valid_attributes
%w(panel_groups panels metrics group priority type title y_label weight id unit label query query_range dashboard)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusMetric
include ActiveModel::Model
attr_accessor :id, :unit, :label, :query, :query_range
validates :unit, presence: true
validates :query, presence: true, unless: :query_range
validates :query_range, presence: true, unless: :query
def self.from_json(json_content)
metric = PrometheusMetric.new(
id: json_content['id'],
unit: json_content['unit'],
label: json_content['label'],
query: json_content['query'],
query_range: json_content['query_range']
)
metric.tap(&:validate!)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusPanel
include ActiveModel::Model
attr_accessor :type, :title, :y_label, :weight, :metrics
validates :title, presence: true
validates :metrics, presence: true
def self.from_json(json_content)
panel = new(
type: json_content['type'],
title: json_content['title'],
y_label: json_content['y_label'],
weight: json_content['weight'],
metrics: json_content['metrics'].map { |metric| PrometheusMetric.from_json(metric) }
)
panel.tap(&:validate!)
end
end
end
# frozen_string_literal: true
module PerformanceMonitoring
class PrometheusPanelGroup
include ActiveModel::Model
attr_accessor :group, :priority, :panels
validates :group, presence: true
validates :panels, presence: true
def self.from_json(json_content)
panel_group = new(
group: json_content['group'],
priority: json_content['priority'],
panels: json_content['panels'].map { |panel| PrometheusPanel.from_json(panel) }
)
panel_group.tap(&:validate!)
end
end
end
---
title: Add validation for custom PrometheusDashboard
merge_request: 22893
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
describe PerformanceMonitoring::PrometheusDashboard do
let(:json_content) do
{
"dashboard" => "Dashboard Title",
"panel_groups" => [{
"group" => "Group Title",
"panels" => [{
"type" => "area-chart",
"title" => "Chart Title",
"y_label" => "Y-Axis",
"metrics" => [{
"id" => "metric_of_ages",
"unit" => "count",
"label" => "Metric of Ages",
"query_range" => "http_requests_total"
}]
}]
}]
}
end
describe '.from_json' do
subject { described_class.from_json(json_content) }
it 'creates a PrometheusDashboard object' do
expect(subject).to be_a PerformanceMonitoring::PrometheusDashboard
expect(subject.dashboard).to eq(json_content['dashboard'])
expect(subject.panel_groups).to all(be_a PerformanceMonitoring::PrometheusPanelGroup)
end
describe 'validations' do
context 'when dashboard is missing' do
before do
json_content['dashboard'] = nil
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
context 'when panel groups are missing' do
before do
json_content['panel_groups'] = []
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
end
end
describe '#to_yaml' do
let(:expected_yaml) do
"---\npanel_groups:\n- panels:\n - metrics:\n - id: metric_of_ages\n unit: count\n label: Metric of Ages\n query: \n query_range: http_requests_total\n type: area-chart\n title: Chart Title\n y_label: Y-Axis\n weight: \n group: Group Title\n priority: \ndashboard: Dashboard Title\n"
end
let(:prometheus_dashboard) { described_class.from_json(json_content) }
let(:subject) { prometheus_dashboard.to_yaml }
it { is_expected.to eq(expected_yaml) }
end
end
# frozen_string_literal: true
require 'spec_helper'
describe PerformanceMonitoring::PrometheusMetric do
let(:json_content) do
{
"id" => "metric_of_ages",
"unit" => "count",
"label" => "Metric of Ages",
"query_range" => "http_requests_total"
}
end
describe '.from_json' do
subject { described_class.from_json(json_content) }
it 'creates a PrometheusMetric object' do
expect(subject).to be_a PerformanceMonitoring::PrometheusMetric
expect(subject.id).to eq(json_content['id'])
expect(subject.unit).to eq(json_content['unit'])
expect(subject.label).to eq(json_content['label'])
expect(subject.query_range).to eq(json_content['query_range'])
end
describe 'validations' do
context 'when unit is missing' do
before do
json_content['unit'] = nil
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
context 'when query and query_range is missing' do
before do
json_content['query_range'] = nil
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
context 'when query_range is missing but query is available' do
before do
json_content['query_range'] = nil
json_content['query'] = 'http_requests_total'
end
subject { described_class.from_json(json_content) }
it { is_expected.to be_valid }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe PerformanceMonitoring::PrometheusPanelGroup do
let(:json_content) do
{
"group" => "Group Title",
"panels" => [{
"type" => "area-chart",
"title" => "Chart Title",
"y_label" => "Y-Axis",
"metrics" => [{
"id" => "metric_of_ages",
"unit" => "count",
"label" => "Metric of Ages",
"query_range" => "http_requests_total"
}]
}]
}
end
describe '.from_json' do
subject { described_class.from_json(json_content) }
it 'creates a PrometheusPanelGroup object' do
expect(subject).to be_a PerformanceMonitoring::PrometheusPanelGroup
expect(subject.group).to eq(json_content['group'])
expect(subject.panels).to all(be_a PerformanceMonitoring::PrometheusPanel)
end
describe 'validations' do
context 'when group is missing' do
before do
json_content['group'] = nil
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
context 'when panels are missing' do
before do
json_content['panels'] = []
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe PerformanceMonitoring::PrometheusPanel do
let(:json_content) do
{
"type" => "area-chart",
"title" => "Chart Title",
"y_label" => "Y-Axis",
"weight" => 1,
"metrics" => [{
"id" => "metric_of_ages",
"unit" => "count",
"label" => "Metric of Ages",
"query_range" => "http_requests_total"
}]
}
end
describe '.from_json' do
subject { described_class.from_json(json_content) }
it 'creates a PrometheusPanelGroup object' do
expect(subject).to be_a PerformanceMonitoring::PrometheusPanel
expect(subject.type).to eq(json_content['type'])
expect(subject.title).to eq(json_content['title'])
expect(subject.y_label).to eq(json_content['y_label'])
expect(subject.weight).to eq(json_content['weight'])
expect(subject.metrics).to all(be_a PerformanceMonitoring::PrometheusMetric)
end
describe 'validations' do
context 'when title is missing' do
before do
json_content['title'] = nil
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
context 'when metrics are missing' do
before do
json_content['metrics'] = []
end
subject { described_class.from_json(json_content) }
it { expect { subject }.to raise_error(ActiveModel::ValidationError) }
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment