prometheus_exporter/test/middleware_test.rb

229 lines
7.1 KiB
Ruby

# frozen_string_literal: true
require "minitest/stub_const"
require_relative "test_helper"
require "rack/test"
require "prometheus_exporter/middleware"
class PrometheusExporterMiddlewareTest < Minitest::Test
include Rack::Test::Methods
attr_reader :app
class FakeClient
attr_reader :last_send
def send_json(args)
@last_send = args
end
end
def client
@client ||= FakeClient.new
end
def inner_app
Proc.new { |env| [200, {}, "OK"] }
end
def now
@now = Process.clock_gettime(Process::CLOCK_REALTIME)
end
def configure_middleware(overrides = {})
config = { client: client, instrument: :alias_method }.merge(overrides)
@app = PrometheusExporter::Middleware.new(inner_app, config)
def @app.request_start
1234567891.123
end
end
def assert_valid_headers_response(delta = 0.5)
configure_middleware
get "/"
assert last_response.ok?
refute_nil client.last_send
refute_nil client.last_send[:queue_time]
assert_in_delta 1, client.last_send[:queue_time], delta
end
def assert_invalid_headers_response
configure_middleware
get "/"
assert last_response.ok?
refute_nil client.last_send
assert_nil client.last_send[:queue_time]
end
def test_converting_apache_request_start
configure_middleware
now_microsec = "1234567890123456"
header "X-Request-Start", "t=#{now_microsec}"
assert_valid_headers_response
end
def test_converting_nginx_request_start
configure_middleware
now = "1234567890.123"
header "X-Request-Start", "t=#{now}"
assert_valid_headers_response
end
def test_request_start_in_wrong_format
configure_middleware
header "X-Request-Start", ""
assert_invalid_headers_response
end
def test_converting_amzn_trace_id_start
configure_middleware
now = "1234567890"
header "X-Amzn-Trace-Id", "Root=1-#{now.to_i.to_s(16)}-abc123"
assert_valid_headers_response
end
def test_amzn_trace_id_in_wrong_format
configure_middleware
header "X-Amzn-Trace-Id", ""
assert_invalid_headers_response
end
def test_redis_5_call_patching
RedisValidationMiddleware.reset!
configure_middleware
# protocol 2 is the old redis protocol, it uses no preamble so you don't leak HELLO
# calls
redis_config = RedisClient.config(host: "127.0.0.1", port: 10, protocol: 2)
redis = redis_config.new_pool(timeout: 0.5, size: 1)
PrometheusExporter::Instrumentation::MethodProfiler.start
redis.call("PING") # => "PONG"
redis.call("PING") # => "PONG"
results = PrometheusExporter::Instrumentation::MethodProfiler.stop
assert(2, results[:redis][:calls])
assert_equal(2, RedisValidationMiddleware.call_calls)
assert_equal(0, RedisValidationMiddleware.call_pipelined_calls)
end
def test_redis_5_call_pipelined_patching
RedisValidationMiddleware.reset!
configure_middleware
# protocol 2 is the old redis protocol, it uses no preamble so you don't leak HELLO
# calls
redis_config = RedisClient.config(host: "127.0.0.1", port: 10, protocol: 2)
redis = redis_config.new_pool(timeout: 0.5, size: 1)
PrometheusExporter::Instrumentation::MethodProfiler.start
redis.pipelined do |pipeline|
pipeline.call("PING") # => "PONG"
pipeline.call("PING") # => "PONG"
end
assert_equal(0, RedisValidationMiddleware.call_calls)
assert_equal(1, RedisValidationMiddleware.call_pipelined_calls)
results = PrometheusExporter::Instrumentation::MethodProfiler.stop
assert_equal(1, results[:redis][:calls])
end
def test_patch_called_with_prepend_instrument
Object.stub_const(:Redis, Module) do
::Redis.stub_const(:Client) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Redis::Client, Array, :redis], instrument: :prepend
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware(instrument: :prepend)
end
mock.verify
end
end
Object.stub_const(:PG, Module) do
::PG.stub_const(:Connection) do
mock = Minitest::Mock.new
mock.expect :call, nil, [PG::Connection, Array, :sql], instrument: :prepend
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware(instrument: :prepend)
end
mock.verify
end
end
Object.stub_const(:Mysql2, Module) do
::Mysql2.stub_consts({ Client: nil, Statement: nil, Result: nil }) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Mysql2::Client, Array, :sql], instrument: :prepend
mock.expect :call, nil, [Mysql2::Statement, Array, :sql], instrument: :prepend
mock.expect :call, nil, [Mysql2::Result, Array, :sql], instrument: :prepend
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware(instrument: :prepend)
end
mock.verify
end
end
Object.stub_const(:Dalli, Module) do
::Dalli.stub_const(:Client) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Dalli::Client, Array, :memcache], instrument: :prepend
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware(instrument: :prepend)
end
mock.verify
end
end
end
def test_patch_called_with_alias_method_instrument
Object.stub_const(:Redis, Module) do
# must be less than version 5 for this instrumentation
::Redis.stub_const(:VERSION, "4.0.4") do
::Redis.stub_const(:Client) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Redis::Client, Array, :redis], instrument: :alias_method
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware
end
mock.verify
end
end
end
Object.stub_const(:PG, Module) do
::PG.stub_const(:Connection) do
mock = Minitest::Mock.new
mock.expect :call, nil, [PG::Connection, Array, :sql], instrument: :alias_method
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware
end
mock.verify
end
end
Object.stub_const(:Mysql2, Module) do
::Mysql2.stub_consts({ Client: nil, Statement: nil, Result: nil }) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Mysql2::Client, Array, :sql], instrument: :alias_method
mock.expect :call, nil, [Mysql2::Statement, Array, :sql], instrument: :alias_method
mock.expect :call, nil, [Mysql2::Result, Array, :sql], instrument: :alias_method
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware
end
mock.verify
end
end
Object.stub_const(:Dalli, Module) do
::Dalli.stub_const(:Client) do
mock = Minitest::Mock.new
mock.expect :call, nil, [Dalli::Client, Array, :memcache], instrument: :alias_method
::PrometheusExporter::Instrumentation::MethodProfiler.stub(:patch, mock) do
configure_middleware(instrument: :alias_method)
end
mock.verify
end
end
end
end