191 lines
5.4 KiB
Go
191 lines
5.4 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/sdk/metric"
|
|
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
|
)
|
|
|
|
func TestProcessConfigValidate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
require.NoError(t, ProcessConfig{
|
|
TracesExporter: "none",
|
|
MetricsExporter: "none",
|
|
}.Validate())
|
|
|
|
require.NoError(t, ProcessConfig{
|
|
TracesExporter: "otlp",
|
|
MetricsExporter: "otlp",
|
|
TracesProtocol: "grpc",
|
|
MetricsProtocol: "http/protobuf",
|
|
}.Validate())
|
|
|
|
require.Error(t, ProcessConfig{
|
|
TracesExporter: "stdout",
|
|
MetricsExporter: "none",
|
|
}.Validate())
|
|
|
|
require.Error(t, ProcessConfig{
|
|
TracesExporter: "none",
|
|
MetricsExporter: "kafka",
|
|
}.Validate())
|
|
|
|
require.Error(t, ProcessConfig{
|
|
TracesExporter: "otlp",
|
|
MetricsExporter: "none",
|
|
TracesProtocol: "thrift",
|
|
}.Validate())
|
|
}
|
|
|
|
func TestNewWithProvidersBuildsRuntime(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reader := metric.NewManualReader()
|
|
meterProvider := metric.NewMeterProvider(metric.WithReader(reader))
|
|
|
|
runtime, err := NewWithProviders(meterProvider, nil)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, runtime)
|
|
require.NotNil(t, runtime.MeterProvider())
|
|
require.NotNil(t, runtime.TracerProvider())
|
|
}
|
|
|
|
func TestRecordHelpersEmitInstruments(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reader := metric.NewManualReader()
|
|
meterProvider := metric.NewMeterProvider(metric.WithReader(reader))
|
|
runtime, err := NewWithProviders(meterProvider, nil)
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
|
|
runtime.RecordInternalHTTPRequest(ctx, []attribute.KeyValue{
|
|
attribute.String("route", "/healthz"),
|
|
attribute.String("method", "GET"),
|
|
attribute.String("status_code", "200"),
|
|
}, 10*time.Millisecond)
|
|
runtime.RecordRegisterRuntimeOutcome(ctx, "success", "")
|
|
runtime.RecordTurnGenerationOutcome(ctx, "success", "", "scheduler")
|
|
runtime.RecordCommandExecuteOutcome(ctx, "success", "")
|
|
runtime.RecordOrderPutOutcome(ctx, "success", "")
|
|
runtime.RecordReportGetOutcome(ctx, "success", "")
|
|
runtime.RecordBanishOutcome(ctx, "success", "")
|
|
runtime.RecordHealthEventConsumed(ctx)
|
|
runtime.RecordLobbyEventPublished(ctx, "runtime_snapshot_update")
|
|
runtime.RecordNotificationPublishAttempt(ctx, "game.turn.ready", "ok")
|
|
runtime.RecordMembershipCacheResult(ctx, "hit")
|
|
runtime.RecordEngineCall(ctx, "init", 25*time.Millisecond)
|
|
|
|
var rm metricdata.ResourceMetrics
|
|
require.NoError(t, reader.Collect(ctx, &rm))
|
|
|
|
names := collectInstrumentNames(rm)
|
|
expected := []string{
|
|
"gamemaster.internal_http.requests",
|
|
"gamemaster.internal_http.duration",
|
|
"gamemaster.register_runtime.outcomes",
|
|
"gamemaster.turn_generation.outcomes",
|
|
"gamemaster.command_execute.outcomes",
|
|
"gamemaster.order_put.outcomes",
|
|
"gamemaster.report_get.outcomes",
|
|
"gamemaster.banish.outcomes",
|
|
"gamemaster.health_events.consumed",
|
|
"gamemaster.lobby_events.published",
|
|
"gamemaster.notification.publish_attempts",
|
|
"gamemaster.membership_cache.hits",
|
|
"gamemaster.engine_call.latency",
|
|
}
|
|
for _, name := range expected {
|
|
require.Contains(t, names, name, "expected instrument %s to be recorded", name)
|
|
}
|
|
}
|
|
|
|
func collectInstrumentNames(rm metricdata.ResourceMetrics) map[string]struct{} {
|
|
names := make(map[string]struct{})
|
|
for _, sm := range rm.ScopeMetrics {
|
|
for _, m := range sm.Metrics {
|
|
names[m.Name] = struct{}{}
|
|
}
|
|
}
|
|
return names
|
|
}
|
|
|
|
type stubRuntimeProbe struct {
|
|
counts map[string]int
|
|
err error
|
|
}
|
|
|
|
func (probe stubRuntimeProbe) CountByStatus(_ context.Context) (map[string]int, error) {
|
|
return probe.counts, probe.err
|
|
}
|
|
|
|
type stubSchedulerProbe struct {
|
|
due int
|
|
err error
|
|
}
|
|
|
|
func (probe stubSchedulerProbe) CountDue(_ context.Context) (int, error) {
|
|
return probe.due, probe.err
|
|
}
|
|
|
|
type stubVersionsProbe struct {
|
|
count int
|
|
err error
|
|
}
|
|
|
|
func (probe stubVersionsProbe) CountVersions(_ context.Context) (int, error) {
|
|
return probe.count, probe.err
|
|
}
|
|
|
|
func TestRegisterGaugesEmitsObservations(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reader := metric.NewManualReader()
|
|
meterProvider := metric.NewMeterProvider(metric.WithReader(reader))
|
|
runtime, err := NewWithProviders(meterProvider, nil)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, runtime.RegisterGauges(GaugeDependencies{
|
|
RuntimeRecordsByStatus: stubRuntimeProbe{counts: map[string]int{"running": 3}},
|
|
SchedulerDueGames: stubSchedulerProbe{due: 2},
|
|
EngineVersionsTotal: stubVersionsProbe{count: 5},
|
|
}))
|
|
|
|
var rm metricdata.ResourceMetrics
|
|
require.NoError(t, reader.Collect(context.Background(), &rm))
|
|
|
|
names := collectInstrumentNames(rm)
|
|
require.Contains(t, names, "gamemaster.runtime_records_by_status")
|
|
require.Contains(t, names, "gamemaster.scheduler.due_games")
|
|
require.Contains(t, names, "gamemaster.engine_versions_total")
|
|
}
|
|
|
|
func TestRegisterGaugesRejectsNilDependencies(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reader := metric.NewManualReader()
|
|
meterProvider := metric.NewMeterProvider(metric.WithReader(reader))
|
|
runtime, err := NewWithProviders(meterProvider, nil)
|
|
require.NoError(t, err)
|
|
|
|
require.Error(t, runtime.RegisterGauges(GaugeDependencies{
|
|
SchedulerDueGames: stubSchedulerProbe{},
|
|
EngineVersionsTotal: stubVersionsProbe{},
|
|
}))
|
|
require.Error(t, runtime.RegisterGauges(GaugeDependencies{
|
|
RuntimeRecordsByStatus: stubRuntimeProbe{},
|
|
EngineVersionsTotal: stubVersionsProbe{},
|
|
}))
|
|
require.Error(t, runtime.RegisterGauges(GaugeDependencies{
|
|
RuntimeRecordsByStatus: stubRuntimeProbe{},
|
|
SchedulerDueGames: stubSchedulerProbe{},
|
|
}))
|
|
}
|