-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from senid231/add-send-metrics-matcher
add send_metrics matcher, add base_stats instrumentation tests
- Loading branch information
Showing
6 changed files
with
194 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,17 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'prometheus_exporter/client' | ||
require_relative 'rspec/matchers' | ||
require_relative 'rspec/test_client' | ||
|
||
# Setups default client before it used anywhere. | ||
# use `include_examples :observes_prometheus_metrics` in specs | ||
PrometheusExporter::Client.default = PrometheusExporter::Ext::RSpec::TestClient.instance | ||
|
||
RSpec.configure do |config| | ||
config.include PrometheusExporter::Ext::RSpec::Matchers | ||
|
||
config.before do | ||
PrometheusExporter::Ext::RSpec::TestClient.instance.reset | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# frozen_string_literal: true | ||
|
||
module PrometheusExporter::Ext::RSpec | ||
class SendMetricsMatcher | ||
include RSpec::Matchers::DSL::DefaultImplementations | ||
include RSpec::Matchers | ||
include RSpec::Matchers::Composable | ||
|
||
attr_reader :expected, :actual | ||
|
||
def initialize(expected) | ||
@expected = expected&.map { |metric| deep_stringify_keys(metric) } | ||
@ordered = false | ||
@times = nil | ||
end | ||
|
||
def name | ||
'sends metrics to prometheus' | ||
end | ||
|
||
def supports_block_expectations? | ||
true | ||
end | ||
|
||
def matches?(actual_proc) | ||
raise ArgumentError, "#{name} matcher supports only block expectations" unless actual_proc.is_a?(Proc) | ||
|
||
metrics_before = PrometheusExporter::Ext::RSpec::TestClient.instance.metrics | ||
actual_proc.call | ||
metrics_after = PrometheusExporter::Ext::RSpec::TestClient.instance.metrics - metrics_before | ||
@actual = metrics_after.map { |metric| deep_stringify_keys(metric) } | ||
|
||
if expected | ||
expected_value = @ordered ? expected : match_array(expected) | ||
values_match?(expected_value, actual) | ||
elsif @times | ||
values_match?(@times, actual.size) | ||
else | ||
actual.size >= 1 | ||
end | ||
end | ||
|
||
def failure_message | ||
if expected | ||
expected_value = @ordered ? expected : match_array(expected) | ||
+"expected #{name} to receive #{description_of(expected_value)}, but got\n #{description_of(actual)}" | ||
elsif @times | ||
values_match?(@times, actual.size) | ||
+"expected #{name} to receive #{@times} metrics, but got #{actual.size}\n #{description_of(actual)}" | ||
else | ||
actual.size | ||
+"expected #{name} to receive more than 1 metric, but got #{actual.size}\n #{description_of(actual)}" | ||
end | ||
end | ||
|
||
def ordered | ||
raise ArgumentError, 'ordered cannot be when expected not provided' if expected.nil? | ||
raise ArgumentError, 'ordered cannot be used with times' if @times | ||
|
||
@ordered = true | ||
self | ||
end | ||
|
||
def times(qty) | ||
raise ArgumentError, 'times argument must be an integer' unless qty.is_a?(Integer) | ||
raise ArgumentError, 'times argument must be >= 1' unless qty >= 1 | ||
raise ArgumentError, 'ordered cannot be when expected is provided' unless expected.nil? | ||
raise ArgumentError, 'ordered cannot be used with times' if @ordered | ||
|
||
@times = qty | ||
self | ||
end | ||
|
||
def description_of(object) | ||
RSpec::Support::ObjectFormatter.new(nil).format(object) | ||
end | ||
|
||
private | ||
|
||
def deep_stringify_keys(hash) | ||
hash.transform_keys(&:to_s).transform_values do |value| | ||
value.is_a?(Hash) ? deep_stringify_keys(value) : value | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'singleton' | ||
|
||
module PrometheusExporter::Ext::RSpec | ||
class TestClient | ||
include Singleton | ||
|
||
def initialize | ||
super | ||
reset | ||
end | ||
|
||
def metrics | ||
@metrics.dup | ||
end | ||
|
||
def send_json(data) | ||
@metrics << data | ||
end | ||
|
||
def reset | ||
@metrics = [] | ||
end | ||
|
||
def stop | ||
nil | ||
end | ||
end | ||
end |
50 changes: 50 additions & 0 deletions
50
spec/prometheus_exporter/ext/instrumentation/base_stats_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe PrometheusExporter::Ext::Instrumentation::BaseStats do | ||
subject do | ||
instrumentation.collect(data_list) | ||
end | ||
|
||
let(:instrumentation) { TestInstrumentation.new } | ||
let(:data_list) do | ||
[ | ||
{ foo: 123, bar: 456, labels: { qwe: 'asd' } }, | ||
{ foo: 124, bar: 457, labels: { qwe: 'zxc' } } | ||
] | ||
end | ||
|
||
it 'sends metrics' do | ||
expect { subject }.to send_metrics | ||
end | ||
|
||
it 'sends exactly 2 metrics' do | ||
expect { subject }.to send_metrics.times(2) | ||
end | ||
|
||
it 'sends correct metrics' do | ||
expect { subject }.to send_metrics( | ||
[ | ||
{ | ||
type: 'test', | ||
foo: 123, bar: 456, | ||
labels: { qwe: 'asd' }, | ||
metric_labels: {} | ||
}, | ||
{ | ||
type: 'test', | ||
foo: 124, bar: 457, | ||
labels: { qwe: 'zxc' }, | ||
metric_labels: {} | ||
} | ||
] | ||
) | ||
end | ||
|
||
context 'with empty data list' do | ||
let(:data_list) { [] } | ||
|
||
it 'sends correct metrics' do | ||
expect { subject }.not_to send_metrics | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters