package metricsintentpub_test import ( "context" "errors" "testing" "galaxy/lobby/internal/adapters/metricsintentpub" "galaxy/lobby/internal/telemetry" "galaxy/notificationintent" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" ) type fakePublisher struct { id string err error } func (f fakePublisher) Publish(_ context.Context, _ notificationintent.Intent) (string, error) { return f.id, f.err } func TestPublisherForwardsAndRecordsOK(t *testing.T) { t.Parallel() reader := sdkmetric.NewManualReader() provider := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) t.Cleanup(func() { _ = provider.Shutdown(context.Background()) }) runtime, err := telemetry.NewWithProviders(provider, nil) require.NoError(t, err) pub := metricsintentpub.New(fakePublisher{id: "0-1"}, runtime) id, err := pub.Publish(context.Background(), notificationintent.Intent{ NotificationType: notificationintent.NotificationTypeLobbyApplicationSubmitted, }) require.NoError(t, err) assert.Equal(t, "0-1", id) rm := collect(t, reader) require.Contains(t, sumValues(rm, "lobby.notification.publish_attempts"), counterPoint{ notificationType: "lobby.application.submitted", result: "ok", value: 1, }) } func TestPublisherRecordsErrorOnInnerFailure(t *testing.T) { t.Parallel() reader := sdkmetric.NewManualReader() provider := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) t.Cleanup(func() { _ = provider.Shutdown(context.Background()) }) runtime, err := telemetry.NewWithProviders(provider, nil) require.NoError(t, err) pub := metricsintentpub.New(fakePublisher{err: errors.New("boom")}, runtime) _, err = pub.Publish(context.Background(), notificationintent.Intent{ NotificationType: notificationintent.NotificationTypeLobbyApplicationSubmitted, }) require.Error(t, err) rm := collect(t, reader) require.Contains(t, sumValues(rm, "lobby.notification.publish_attempts"), counterPoint{ notificationType: "lobby.application.submitted", result: "error", value: 1, }) } type counterPoint struct { notificationType string result string value int64 } func collect(t *testing.T, reader sdkmetric.Reader) metricdata.ResourceMetrics { t.Helper() var rm metricdata.ResourceMetrics require.NoError(t, reader.Collect(context.Background(), &rm)) return rm } func sumValues(rm metricdata.ResourceMetrics, name string) []counterPoint { var points []counterPoint for _, scope := range rm.ScopeMetrics { for _, m := range scope.Metrics { if m.Name != name { continue } sum, ok := m.Data.(metricdata.Sum[int64]) if !ok { continue } for _, point := range sum.DataPoints { notificationType, _ := point.Attributes.Value("notification_type") result, _ := point.Attributes.Value("result") points = append(points, counterPoint{ notificationType: notificationType.AsString(), result: result.AsString(), value: point.Value, }) } } } return points }