Skip to content

Commit

Permalink
Add/refactor some unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gl-johnson authored and jtuttle committed Aug 4, 2023
1 parent ae920bd commit 1fb0fad
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 105 deletions.
6 changes: 2 additions & 4 deletions lib/monitoring/prometheus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module Monitoring
module Prometheus
extend self

attr_reader :registry

def setup(options = {})
@registry = options[:registry] || ::Prometheus::Client::Registry.new
@metrics_dir_path = ENV['CONJUR_METRICS_DIR'] || '/tmp/prometheus'
Expand All @@ -21,10 +23,6 @@ def setup(options = {})
setup_metrics
end

def registry
@registry
end

protected

def clear_data_store
Expand Down
98 changes: 31 additions & 67 deletions spec/lib/monitoring/metrics_spec.rb
Original file line number Diff line number Diff line change
@@ -1,75 +1,39 @@
require 'prometheus/client/formats/text'
require 'monitoring/prometheus'
require 'monitoring/metrics'
require 'prometheus/client'

class SampleMetric
def setup(registry, pubsub)
registry.register(::Prometheus::Client::Gauge.new(
:test_gauge,
docstring: '...',
labels: [:test_label]
))

pubsub.subscribe("sample_test_gauge") do |payload|
metric = registry.get(:test_gauge)
metric.set(payload[:value], labels: payload[:labels])
end
RSpec.describe Monitoring::Metrics do
class MockMetric
# does nothing
end
end

describe Monitoring::Prometheus do
let(:registry) {
Monitoring::Prometheus.setup
Monitoring::Prometheus.registry
}

it 'creates a valid registry and allows metrics' do
gauge = registry.gauge(:foo, docstring: '...', labels: [:bar])
gauge.set(21.534, labels: { bar: 'test' })

expect(gauge.get(labels: { bar: 'test' })).to eql(21.534)
end

it 'can use Pub/Sub events to update metrics on the registry' do
gauge = registry.gauge(:foo, docstring: '...', labels: [:bar])

pub_sub = Monitoring::PubSub.instance
pub_sub.subscribe("foo_event_name") do |payload|
labels = {
bar: payload[:bar]
}
gauge.set(payload[:value], labels: labels)
describe '#create_metric' do
context 'with valid metric type' do
it 'creates a gauge metric' do
expect(Monitoring::Metrics).to receive(:create_gauge_metric).with(MockMetric)
Monitoring::Metrics.create_metric(MockMetric, :gauge)
end

it 'creates a counter metric' do
expect(Monitoring::Metrics).to receive(:create_counter_metric).with(MockMetric)
Monitoring::Metrics.create_metric(MockMetric, :counter)
end

it 'creates a histogram metric' do
expect(Monitoring::Metrics).to receive(:create_histogram_metric).with(MockMetric)
Monitoring::Metrics.create_metric(MockMetric, :histogram)
end

it 'creates a histogram metric (string)' do
expect(Monitoring::Metrics).to receive(:create_histogram_metric).with(MockMetric)
Monitoring::Metrics.create_metric(MockMetric, 'histogram')
end
end

pub_sub.publish("foo_event_name", value: 100, bar: "omicron")
expect(gauge.get(labels: { bar: "omicron" })).to eql(100.0)
end

context 'when given a list of metrics to setup' do
before do
@metric_obj = SampleMetric.new
@registry = ::Prometheus::Client::Registry.new
@mock_pubsub = double("Mock Monitoring::PubSub")
end

def prometheus_setup
Monitoring::Prometheus.setup(
registry: @registry,
metrics: [ @metric_obj ],
pubsub: @mock_pubsub
)
end

it 'calls .setup for the metric class' do
expect(@metric_obj).to receive(:setup).with(@registry, @mock_pubsub)
prometheus_setup
end

it 'adds custom metric definitions to the global registry and subscribes to related Pub/Sub events' do
expect(@mock_pubsub).to receive(:subscribe).with("sample_test_gauge")
prometheus_setup

sample_metric = @registry.get(:test_gauge)
expect(sample_metric).not_to be_nil
context 'with invalid metric type' do
it 'raises an error' do
expect { Monitoring::Metrics.create_metric(MockMetric, :invalid_type) }
.to raise_error(Errors::Monitoring::InvalidOrMissingMetricType)
end
end
end
end
4 changes: 2 additions & 2 deletions spec/lib/monitoring/middleware/prometheus_collector_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@

it 'returns the app response' do
env['PATH_INFO'] = "/foo"
status, _headers, _response = subject.call(env)
status, _headers, response = subject.call(env)

expect(status).to eql(200)
expect(_response.first).to eql('OK')
expect(response.first).to eql('OK')
end

it 'traces request information' do
Expand Down
16 changes: 8 additions & 8 deletions spec/lib/monitoring/middleware/prometheus_exporter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
context 'when requesting app endpoints' do
it 'returns the app response' do
env['PATH_INFO'] = "/foo"
status, _headers, _response = subject.call(env)
status, _headers, response = subject.call(env)

expect(status).to eql(200)
expect(_response.first).to eql('OK')
expect(response.first).to eql('OK')
end
end

Expand All @@ -44,11 +44,11 @@
env['PATH_INFO'] = path
env['HTTP_ACCEPT'] = headers.values[0] if headers.values[0]

status, _headers, _response = subject.call(env)
status, headers, response = subject.call(env)

expect(status).to eql(200)
expect(_headers['Content-Type']).to eql(fmt::CONTENT_TYPE)
expect(_response.first).to eql(fmt.marshal(registry))
expect(headers['Content-Type']).to eql(fmt::CONTENT_TYPE)
expect(response.first).to eql(fmt.marshal(registry))

end
end
Expand All @@ -60,11 +60,11 @@
env['PATH_INFO'] = path
env['HTTP_ACCEPT'] = headers.values[0] if headers.values[0]

status, _headers, _response = subject.call(env)
status, headers, response = subject.call(env)

expect(status).to eql(406)
expect(_headers['Content-Type']).to eql('text/plain')
expect(_response.first).to eql(message)
expect(headers['Content-Type']).to eql('text/plain')
expect(response.first).to eql(message)
end
end

Expand Down
75 changes: 75 additions & 0 deletions spec/lib/monitoring/prometheus_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require 'prometheus/client/formats/text'
require 'monitoring/prometheus'

class SampleMetric
def setup(registry, pubsub)
registry.register(::Prometheus::Client::Gauge.new(
:test_gauge,
docstring: '...',
labels: [:test_label]
))

pubsub.subscribe("sample_test_gauge") do |payload|
metric = registry.get(:test_gauge)
metric.set(payload[:value], labels: payload[:labels])
end
end
end

describe Monitoring::Prometheus do
let(:registry) {
Monitoring::Prometheus.setup
Monitoring::Prometheus.registry
}

it 'creates a valid registry and allows metrics' do
gauge = registry.gauge(:foo, docstring: '...', labels: [:bar])
gauge.set(21.534, labels: { bar: 'test' })

expect(gauge.get(labels: { bar: 'test' })).to eql(21.534)
end

it 'can use Pub/Sub events to update metrics on the registry' do
gauge = registry.gauge(:foo, docstring: '...', labels: [:bar])

pub_sub = Monitoring::PubSub.instance
pub_sub.subscribe("foo_event_name") do |payload|
labels = {
bar: payload[:bar]
}
gauge.set(payload[:value], labels: labels)
end

pub_sub.publish("foo_event_name", value: 100, bar: "omicron")
expect(gauge.get(labels: { bar: "omicron" })).to eql(100.0)
end

context 'when given a list of metrics to setup' do
before do
@metric_obj = SampleMetric.new
@registry = ::Prometheus::Client::Registry.new
@mock_pubsub = double("Mock Monitoring::PubSub")
end

def prometheus_setup
Monitoring::Prometheus.setup(
registry: @registry,
metrics: [ @metric_obj ],
pubsub: @mock_pubsub
)
end

it 'calls .setup for the metric class' do
expect(@metric_obj).to receive(:setup).with(@registry, @mock_pubsub)
prometheus_setup
end

it 'adds custom metric definitions to the global registry and subscribes to related Pub/Sub events' do
expect(@mock_pubsub).to receive(:subscribe).with("sample_test_gauge")
prometheus_setup

sample_metric = @registry.get(:test_gauge)
expect(sample_metric).not_to be_nil
end
end
end
57 changes: 33 additions & 24 deletions spec/lib/monitoring/query_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
require 'monitoring/query_helper'
require 'spec_helper'

describe Monitoring::QueryHelper, type: :request do
let(:queryhelper) { Monitoring::QueryHelper.instance }
RSpec.describe Monitoring::QueryHelper do
describe '#policy_resource_counts' do
it 'returns the correct resource counts' do
allow(Resource).to receive(:group_and_count).and_return([
{ kind: 'resource1', count: 10 },
{ kind: 'resource2', count: 20 }
])

let(:policies_url) { '/policies/rspec/policy/root' }
counts = Monitoring::QueryHelper.instance.policy_resource_counts

let(:current_user) { Role.find_or_create(role_id: 'rspec:user:admin') }
expect(counts).to eq({ 'resource1' => 10, 'resource2' => 20 })
end

let(:token_auth_header) do
bearer_token = Slosilo["authn:rspec"].signed_token(current_user.login)
token_auth_str =
"Token token=\"#{Base64.strict_encode64(bearer_token.to_json)}\""
{ 'HTTP_AUTHORIZATION' => token_auth_str }
end
it 'returns an empty hash if there are no resources' do
allow(Resource).to receive(:group_and_count).and_return([])

def headers_with_auth(payload)
token_auth_header.merge({ 'RAW_POST_DATA' => payload })
end
counts = Monitoring::QueryHelper.instance.policy_resource_counts

before do
Slosilo["authn:rspec"] ||= Slosilo::Key.new
post(policies_url, env: headers_with_auth('[!group test]'))
expect(counts).to eq({})
end
end

it 'returns policy resource counts' do
resource_counts = queryhelper.policy_resource_counts
expect(resource_counts['group']).to equal(1)
end
describe '#policy_role_counts' do
it 'returns the correct role counts' do
allow(Role).to receive(:group_and_count).and_return([
{ kind: 'role1', count: 5 },
{ kind: 'role2', count: 15 }
])

it 'returns policy role counts' do
role_counts = queryhelper.policy_role_counts
expect(role_counts['group']).to equal(1)
end
counts = Monitoring::QueryHelper.instance.policy_role_counts

expect(counts).to eq({ 'role1' => 5, 'role2' => 15 })
end

it 'returns an empty hash if there are no roles' do
allow(Role).to receive(:group_and_count).and_return([])

counts = Monitoring::QueryHelper.instance.policy_role_counts

expect(counts).to eq({})
end
end
end

0 comments on commit 1fb0fad

Please sign in to comment.