229 lines
7.1 KiB
Ruby
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
|