turniere-backend/spec/e2e/http/metrics_spec.rb

98 lines
3.3 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
require 'securerandom'
require_relative '../../../e2e/lib/action_cable_client'
require_relative '../../../e2e/lib/api_client'
RSpec.describe 'Metrics HTTP E2E' do
primary_env_vars = %w[TURNIERE_E2E_EMAIL TURNIERE_E2E_PASSWORD].freeze
before do
missing_vars = primary_env_vars.reject { |name| ENV.key?(name) }
skip("HTTP E2E requires #{missing_vars.join(', ')}") unless missing_vars.empty?
end
let(:base_url) { ENV.fetch('TURNIERE_E2E_BASE_URL', 'http://127.0.0.1:3000') }
let(:owner_email) { ENV.fetch('TURNIERE_E2E_EMAIL') }
let(:owner_password) { ENV.fetch('TURNIERE_E2E_PASSWORD') }
let(:anonymous_client) { TurniereE2E::ApiClient.new(base_url:) }
it 'exposes HTTP request metrics and live websocket connection metrics' do
health_response = anonymous_client.get('/healthz')
metrics_response = anonymous_client.get('/metrics')
expect(health_response[:status]).to eq(200)
expect(metrics_response[:status]).to eq(200)
expect(metrics_response.dig(:headers, 'content-type')).to include('text/plain')
metrics_body = raw_body(metrics_response)
expect(metrics_body).to include('# TYPE turniere_http_requests_total counter')
expect(metrics_body).to match(
/turniere_http_requests_total\{
(?=[^}]*method="GET")
(?=[^}]*controller="health")
(?=[^}]*action="index")
(?=[^}]*status="200")
[^}]*
\}\ [1-9]\d*/x
)
expect(metrics_body).to include('# TYPE turniere_http_request_duration_seconds histogram')
tournament = create_playoff_tournament
cable_client = TurniereE2E::ActionCableClient.new(base_url:)
cable_client.subscribe_timer!(tournament_id: tournament.fetch(:id))
expect(metric_value('turniere_action_cable_connections')).to be >= 1
expect(metric_value('turniere_action_cable_connections_total')).to be >= 1
ensure
cable_client&.close
end
def create_playoff_tournament
owner_client = login_client
unique = SecureRandom.hex(3)
response = owner_client.post('/tournaments', body: {
name: "Metrics #{unique}",
public: false,
teams: Array.new(4) { |index| { name: "Metrics-#{unique}-#{index + 1}" } }
})
expect(response[:status]).to eq(201)
response.fetch(:json)
end
def login_client
client = TurniereE2E::ApiClient.new(base_url:)
response = client.login!(email: owner_email, password: owner_password)
expect(response[:status]).to eq(200)
client
end
def metric_value(metric_name)
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 10
loop do
value = latest_metrics_lines
.grep(/\A#{Regexp.escape(metric_name)}(?:\{| )/)
.map { |line| line.split.last.to_f }
.max
return value unless value.nil?
raise "#{metric_name} not reported" if Process.clock_gettime(Process::CLOCK_MONOTONIC) >= deadline
sleep 0.2
end
end
def latest_metrics_lines
response = anonymous_client.get('/metrics')
expect(response[:status]).to eq(200)
raw_body(response).lines.map(&:strip)
end
def raw_body(response)
response.dig(:json, :raw_body).to_s
end
end