feat: user service

This commit is contained in:
Ilia Denisov
2026-04-10 19:05:02 +02:00
committed by GitHub
parent 710bad712e
commit 23ffcb7535
140 changed files with 33418 additions and 952 deletions
@@ -0,0 +1,717 @@
package authdirectory
import (
"context"
"errors"
"testing"
"time"
"galaxy/user/internal/domain/account"
"galaxy/user/internal/domain/common"
"galaxy/user/internal/domain/entitlement"
"galaxy/user/internal/domain/policy"
"galaxy/user/internal/ports"
"galaxy/user/internal/service/shared"
"galaxy/user/internal/telemetry"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func TestResolverExecute(t *testing.T) {
t.Parallel()
tests := []struct {
name string
store stubAuthDirectoryStore
wantKind string
wantUserID string
wantBlock string
}{
{
name: "existing",
store: stubAuthDirectoryStore{
resolveByEmail: func(_ context.Context, email common.Email) (ports.ResolveByEmailResult, error) {
require.Equal(t, common.Email("pilot@example.com"), email)
return ports.ResolveByEmailResult{
Kind: ports.AuthResolutionKindExisting,
UserID: common.UserID("user-123"),
}, nil
},
},
wantKind: "existing",
wantUserID: "user-123",
},
{
name: "creatable",
store: stubAuthDirectoryStore{
resolveByEmail: func(_ context.Context, email common.Email) (ports.ResolveByEmailResult, error) {
require.Equal(t, common.Email("pilot@example.com"), email)
return ports.ResolveByEmailResult{
Kind: ports.AuthResolutionKindCreatable,
}, nil
},
},
wantKind: "creatable",
},
{
name: "blocked",
store: stubAuthDirectoryStore{
resolveByEmail: func(_ context.Context, email common.Email) (ports.ResolveByEmailResult, error) {
require.Equal(t, common.Email("pilot@example.com"), email)
return ports.ResolveByEmailResult{
Kind: ports.AuthResolutionKindBlocked,
BlockReasonCode: common.ReasonCode("policy_blocked"),
}, nil
},
},
wantKind: "blocked",
wantBlock: "policy_blocked",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
resolver, err := NewResolver(tt.store)
require.NoError(t, err)
result, err := resolver.Execute(context.Background(), ResolveByEmailInput{
Email: " pilot@example.com ",
})
require.NoError(t, err)
require.Equal(t, tt.wantKind, result.Kind)
require.Equal(t, tt.wantUserID, result.UserID)
require.Equal(t, tt.wantBlock, result.BlockReasonCode)
})
}
}
func TestEnsurerExecuteCreatedBuildsInitialRecords(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
ensurer, err := NewEnsurer(stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
require.Equal(t, common.Email("created@example.com"), input.Email)
require.Equal(t, common.UserID("user-created"), input.Account.UserID)
require.Equal(t, common.RaceName("player-test123"), input.Account.RaceName)
require.Equal(t, common.LanguageTag("en-US"), input.Account.PreferredLanguage)
require.Equal(t, common.TimeZoneName("Europe/Kaliningrad"), input.Account.TimeZone)
require.Equal(t, input.Account.UserID, input.Reservation.UserID)
require.Equal(t, input.Account.RaceName, input.Reservation.RaceName)
require.Equal(t, accountTestCanonicalKey(input.Account.RaceName), input.Reservation.CanonicalKey)
require.Equal(t, entitlement.PlanCodeFree, input.Entitlement.PlanCode)
require.False(t, input.Entitlement.IsPaid)
require.Equal(t, input.Account.UserID, input.Entitlement.UserID)
require.Equal(t, entitlement.EntitlementRecordID("entitlement-created"), input.EntitlementRecord.RecordID)
require.Equal(t, input.Account.UserID, input.EntitlementRecord.UserID)
require.Equal(t, input.Entitlement.PlanCode, input.EntitlementRecord.PlanCode)
require.Equal(t, input.Entitlement.StartsAt, input.EntitlementRecord.StartsAt)
require.Equal(t, input.Entitlement.Source, input.EntitlementRecord.Source)
require.Equal(t, input.Entitlement.Actor, input.EntitlementRecord.Actor)
require.Equal(t, input.Entitlement.ReasonCode, input.EntitlementRecord.ReasonCode)
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeCreated,
UserID: input.Account.UserID,
}, nil
},
}, fixedClock{now: now}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{})
require.NoError(t, err)
result, err := ensurer.Execute(context.Background(), EnsureByEmailInput{
Email: "created@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en-us",
TimeZone: "Europe/Kaliningrad",
},
})
require.NoError(t, err)
require.Equal(t, "created", result.Outcome)
require.Equal(t, "user-created", result.UserID)
}
func TestEnsurerExecuteRejectsInvalidRegistrationContext(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input EnsureByEmailInput
wantErr string
}{
{
name: "invalid preferred language",
input: EnsureByEmailInput{
Email: "pilot@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "bad@@tag",
TimeZone: "Europe/Kaliningrad",
},
},
wantErr: "registration_context.preferred_language must be a valid BCP 47 language tag",
},
{
name: "invalid time zone",
input: EnsureByEmailInput{
Email: "pilot@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en",
TimeZone: "Mars/Olympus",
},
},
wantErr: "registration_context.time_zone must be a valid IANA time zone name",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ensurer, err := NewEnsurer(stubAuthDirectoryStore{}, fixedClock{now: time.Unix(1_775_240_000, 0).UTC()}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{})
require.NoError(t, err)
_, err = ensurer.Execute(context.Background(), tt.input)
require.Error(t, err)
require.Equal(t, shared.ErrorCodeInvalidRequest, shared.CodeOf(err))
require.Equal(t, tt.wantErr, err.Error())
})
}
}
func TestEnsurerExecuteRetriesConflicts(t *testing.T) {
t.Parallel()
attempt := 0
ensurer, err := NewEnsurer(stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
attempt++
if attempt == 1 {
return ports.EnsureByEmailResult{}, ports.ErrConflict
}
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeCreated,
UserID: input.Account.UserID,
}, nil
},
}, fixedClock{now: time.Unix(1_775_240_000, 0).UTC()}, &sequenceIDGenerator{
userIDs: []common.UserID{"user-first", "user-second"},
raceNames: []common.RaceName{"player-first", "player-second"},
entitlementRecordIDs: []entitlement.EntitlementRecordID{"entitlement-first", "entitlement-second"},
}, stubRaceNamePolicy{})
require.NoError(t, err)
result, err := ensurer.Execute(context.Background(), EnsureByEmailInput{
Email: "retry@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en",
TimeZone: "UTC",
},
})
require.NoError(t, err)
require.Equal(t, 2, attempt)
require.Equal(t, "user-second", result.UserID)
}
func TestEnsurerExecuteReturnsExistingAndBlocked(t *testing.T) {
t.Parallel()
tests := []struct {
name string
store stubAuthDirectoryStore
want EnsureByEmailResult
}{
{
name: "existing",
store: stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
require.Equal(t, common.Email("pilot@example.com"), input.Email)
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeExisting,
UserID: common.UserID("user-existing"),
}, nil
},
},
want: EnsureByEmailResult{
Outcome: "existing",
UserID: "user-existing",
},
},
{
name: "blocked",
store: stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
require.Equal(t, common.Email("pilot@example.com"), input.Email)
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeBlocked,
BlockReasonCode: common.ReasonCode("policy_blocked"),
}, nil
},
},
want: EnsureByEmailResult{
Outcome: "blocked",
BlockReasonCode: "policy_blocked",
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ensurer, err := NewEnsurer(tt.store, fixedClock{now: time.Unix(1_775_240_000, 0).UTC()}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{})
require.NoError(t, err)
result, err := ensurer.Execute(context.Background(), EnsureByEmailInput{
Email: "pilot@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en",
TimeZone: "UTC",
},
})
require.NoError(t, err)
require.Equal(t, tt.want, result)
})
}
}
func TestEnsurerExecuteCreatedPublishesInitializedEvents(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
publisher := &recordingAuthDomainEventPublisher{}
telemetryRuntime, reader := newObservedAuthTelemetryRuntime(t)
ensurer, err := NewEnsurerWithObservability(stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeCreated,
UserID: input.Account.UserID,
}, nil
},
}, fixedClock{now: now}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{}, nil, telemetryRuntime, publisher, publisher, publisher)
require.NoError(t, err)
result, err := ensurer.Execute(context.Background(), EnsureByEmailInput{
Email: "created@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en-us",
TimeZone: "Europe/Kaliningrad",
},
})
require.NoError(t, err)
require.Equal(t, "created", result.Outcome)
require.Len(t, publisher.profileEvents, 1)
require.Equal(t, ports.ProfileChangedOperationInitialized, publisher.profileEvents[0].Operation)
require.Equal(t, common.Source("auth_registration"), publisher.profileEvents[0].Source)
require.Len(t, publisher.settingsEvents, 1)
require.Equal(t, ports.SettingsChangedOperationInitialized, publisher.settingsEvents[0].Operation)
require.Len(t, publisher.entitlementEvents, 1)
require.Equal(t, ports.EntitlementChangedOperationInitialized, publisher.entitlementEvents[0].Operation)
assertMetricCount(t, reader, "user.user_creation.outcomes", map[string]string{
"outcome": "created",
}, 1)
}
func TestEnsurerExecuteExistingBlockedAndFailedDoNotPublishEvents(t *testing.T) {
t.Parallel()
tests := []struct {
name string
store stubAuthDirectoryStore
input EnsureByEmailInput
wantMetric string
wantErrCode string
wantProfileLen int
}{
{
name: "existing",
store: stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeExisting,
UserID: common.UserID("user-existing"),
}, nil
},
},
input: EnsureByEmailInput{
Email: "pilot@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en",
TimeZone: "UTC",
},
},
wantMetric: "existing",
},
{
name: "blocked",
store: stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeBlocked,
BlockReasonCode: common.ReasonCode("policy_blocked"),
}, nil
},
},
input: EnsureByEmailInput{
Email: "pilot@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en",
TimeZone: "UTC",
},
},
wantMetric: "blocked",
},
{
name: "failed",
store: stubAuthDirectoryStore{},
input: EnsureByEmailInput{
Email: "pilot@example.com",
},
wantMetric: "failed",
wantErrCode: shared.ErrorCodeInvalidRequest,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
publisher := &recordingAuthDomainEventPublisher{}
telemetryRuntime, reader := newObservedAuthTelemetryRuntime(t)
ensurer, err := NewEnsurerWithObservability(tt.store, fixedClock{now: time.Unix(1_775_240_000, 0).UTC()}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{}, nil, telemetryRuntime, publisher, publisher, publisher)
require.NoError(t, err)
_, err = ensurer.Execute(context.Background(), tt.input)
if tt.wantErrCode != "" {
require.Error(t, err)
require.Equal(t, tt.wantErrCode, shared.CodeOf(err))
} else {
require.NoError(t, err)
}
require.Empty(t, publisher.profileEvents)
require.Empty(t, publisher.settingsEvents)
require.Empty(t, publisher.entitlementEvents)
assertMetricCount(t, reader, "user.user_creation.outcomes", map[string]string{
"outcome": tt.wantMetric,
}, 1)
})
}
}
func TestEnsurerExecutePublishFailureDoesNotRollbackCreatedUser(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
publisher := &recordingAuthDomainEventPublisher{err: errors.New("publisher unavailable")}
telemetryRuntime, reader := newObservedAuthTelemetryRuntime(t)
ensurer, err := NewEnsurerWithObservability(stubAuthDirectoryStore{
ensureByEmail: func(_ context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
return ports.EnsureByEmailResult{
Outcome: ports.EnsureByEmailOutcomeCreated,
UserID: input.Account.UserID,
}, nil
},
}, fixedClock{now: now}, fixedIDGenerator{
userID: common.UserID("user-created"),
raceName: common.RaceName("player-test123"),
entitlementRecordID: entitlement.EntitlementRecordID("entitlement-created"),
}, stubRaceNamePolicy{}, nil, telemetryRuntime, publisher, publisher, publisher)
require.NoError(t, err)
result, err := ensurer.Execute(context.Background(), EnsureByEmailInput{
Email: "created@example.com",
RegistrationContext: &RegistrationContext{
PreferredLanguage: "en-us",
TimeZone: "Europe/Kaliningrad",
},
})
require.NoError(t, err)
require.Equal(t, "created", result.Outcome)
require.Len(t, publisher.profileEvents, 1)
require.Len(t, publisher.settingsEvents, 1)
require.Len(t, publisher.entitlementEvents, 1)
assertMetricCount(t, reader, "user.event_publication_failures", map[string]string{
"event_type": ports.ProfileChangedEventType,
}, 1)
assertMetricCount(t, reader, "user.event_publication_failures", map[string]string{
"event_type": ports.SettingsChangedEventType,
}, 1)
assertMetricCount(t, reader, "user.event_publication_failures", map[string]string{
"event_type": ports.EntitlementChangedEventType,
}, 1)
}
func TestBlockByUserIDServiceMapsNotFound(t *testing.T) {
t.Parallel()
service, err := NewBlockByUserIDService(stubAuthDirectoryStore{
blockByUserID: func(context.Context, ports.BlockByUserIDInput) (ports.BlockResult, error) {
return ports.BlockResult{}, ports.ErrNotFound
},
}, fixedClock{now: time.Unix(1_775_240_000, 0).UTC()})
require.NoError(t, err)
_, err = service.Execute(context.Background(), BlockByUserIDInput{
UserID: "user-missing",
ReasonCode: "policy_blocked",
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeSubjectNotFound, shared.CodeOf(err))
}
type stubAuthDirectoryStore struct {
resolveByEmail func(context.Context, common.Email) (ports.ResolveByEmailResult, error)
ensureByEmail func(context.Context, ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error)
existsByUserID func(context.Context, common.UserID) (bool, error)
blockByUserID func(context.Context, ports.BlockByUserIDInput) (ports.BlockResult, error)
blockByEmail func(context.Context, ports.BlockByEmailInput) (ports.BlockResult, error)
}
func (store stubAuthDirectoryStore) ResolveByEmail(ctx context.Context, email common.Email) (ports.ResolveByEmailResult, error) {
if store.resolveByEmail == nil {
return ports.ResolveByEmailResult{}, errors.New("unexpected ResolveByEmail call")
}
return store.resolveByEmail(ctx, email)
}
func (store stubAuthDirectoryStore) ExistsByUserID(ctx context.Context, userID common.UserID) (bool, error) {
if store.existsByUserID == nil {
return false, errors.New("unexpected ExistsByUserID call")
}
return store.existsByUserID(ctx, userID)
}
func (store stubAuthDirectoryStore) EnsureByEmail(ctx context.Context, input ports.EnsureByEmailInput) (ports.EnsureByEmailResult, error) {
if store.ensureByEmail == nil {
return ports.EnsureByEmailResult{}, errors.New("unexpected EnsureByEmail call")
}
return store.ensureByEmail(ctx, input)
}
func (store stubAuthDirectoryStore) BlockByUserID(ctx context.Context, input ports.BlockByUserIDInput) (ports.BlockResult, error) {
if store.blockByUserID == nil {
return ports.BlockResult{}, errors.New("unexpected BlockByUserID call")
}
return store.blockByUserID(ctx, input)
}
func (store stubAuthDirectoryStore) BlockByEmail(ctx context.Context, input ports.BlockByEmailInput) (ports.BlockResult, error) {
if store.blockByEmail == nil {
return ports.BlockResult{}, errors.New("unexpected BlockByEmail call")
}
return store.blockByEmail(ctx, input)
}
type fixedClock struct {
now time.Time
}
func (clock fixedClock) Now() time.Time {
return clock.now
}
type fixedIDGenerator struct {
userID common.UserID
raceName common.RaceName
entitlementRecordID entitlement.EntitlementRecordID
sanctionRecordID policy.SanctionRecordID
limitRecordID policy.LimitRecordID
}
func (generator fixedIDGenerator) NewUserID() (common.UserID, error) {
return generator.userID, nil
}
func (generator fixedIDGenerator) NewInitialRaceName() (common.RaceName, error) {
return generator.raceName, nil
}
func (generator fixedIDGenerator) NewEntitlementRecordID() (entitlement.EntitlementRecordID, error) {
return generator.entitlementRecordID, nil
}
func (generator fixedIDGenerator) NewSanctionRecordID() (policy.SanctionRecordID, error) {
return generator.sanctionRecordID, nil
}
func (generator fixedIDGenerator) NewLimitRecordID() (policy.LimitRecordID, error) {
return generator.limitRecordID, nil
}
type sequenceIDGenerator struct {
userIDs []common.UserID
raceNames []common.RaceName
entitlementRecordIDs []entitlement.EntitlementRecordID
sanctionRecordIDs []policy.SanctionRecordID
limitRecordIDs []policy.LimitRecordID
}
func (generator *sequenceIDGenerator) NewUserID() (common.UserID, error) {
value := generator.userIDs[0]
generator.userIDs = generator.userIDs[1:]
return value, nil
}
func (generator *sequenceIDGenerator) NewInitialRaceName() (common.RaceName, error) {
value := generator.raceNames[0]
generator.raceNames = generator.raceNames[1:]
return value, nil
}
func (generator *sequenceIDGenerator) NewEntitlementRecordID() (entitlement.EntitlementRecordID, error) {
value := generator.entitlementRecordIDs[0]
generator.entitlementRecordIDs = generator.entitlementRecordIDs[1:]
return value, nil
}
func (generator *sequenceIDGenerator) NewSanctionRecordID() (policy.SanctionRecordID, error) {
value := generator.sanctionRecordIDs[0]
generator.sanctionRecordIDs = generator.sanctionRecordIDs[1:]
return value, nil
}
func (generator *sequenceIDGenerator) NewLimitRecordID() (policy.LimitRecordID, error) {
value := generator.limitRecordIDs[0]
generator.limitRecordIDs = generator.limitRecordIDs[1:]
return value, nil
}
type stubRaceNamePolicy struct{}
func (stubRaceNamePolicy) CanonicalKey(raceName common.RaceName) (account.RaceNameCanonicalKey, error) {
return accountTestCanonicalKey(raceName), nil
}
func accountTestCanonicalKey(raceName common.RaceName) account.RaceNameCanonicalKey {
return account.RaceNameCanonicalKey("key:" + raceName.String())
}
type recordingAuthDomainEventPublisher struct {
err error
profileEvents []ports.ProfileChangedEvent
settingsEvents []ports.SettingsChangedEvent
entitlementEvents []ports.EntitlementChangedEvent
}
func (publisher *recordingAuthDomainEventPublisher) PublishProfileChanged(_ context.Context, event ports.ProfileChangedEvent) error {
if err := event.Validate(); err != nil {
return err
}
publisher.profileEvents = append(publisher.profileEvents, event)
return publisher.err
}
func (publisher *recordingAuthDomainEventPublisher) PublishSettingsChanged(_ context.Context, event ports.SettingsChangedEvent) error {
if err := event.Validate(); err != nil {
return err
}
publisher.settingsEvents = append(publisher.settingsEvents, event)
return publisher.err
}
func (publisher *recordingAuthDomainEventPublisher) PublishEntitlementChanged(_ context.Context, event ports.EntitlementChangedEvent) error {
if err := event.Validate(); err != nil {
return err
}
publisher.entitlementEvents = append(publisher.entitlementEvents, event)
return publisher.err
}
func newObservedAuthTelemetryRuntime(t *testing.T) (*telemetry.Runtime, *sdkmetric.ManualReader) {
t.Helper()
reader := sdkmetric.NewManualReader()
meterProvider := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader))
tracerProvider := sdktrace.NewTracerProvider()
runtime, err := telemetry.NewWithProviders(meterProvider, tracerProvider)
require.NoError(t, err)
return runtime, reader
}
func assertMetricCount(t *testing.T, reader *sdkmetric.ManualReader, metricName string, wantAttrs map[string]string, wantValue int64) {
t.Helper()
var resourceMetrics metricdata.ResourceMetrics
require.NoError(t, reader.Collect(context.Background(), &resourceMetrics))
for _, scopeMetrics := range resourceMetrics.ScopeMetrics {
for _, metric := range scopeMetrics.Metrics {
if metric.Name != metricName {
continue
}
sum, ok := metric.Data.(metricdata.Sum[int64])
require.True(t, ok)
for _, point := range sum.DataPoints {
if hasMetricAttributes(point.Attributes.ToSlice(), wantAttrs) {
require.Equal(t, wantValue, point.Value)
return
}
}
}
}
require.Failf(t, "test failed", "metric %q with attrs %v not found", metricName, wantAttrs)
}
func hasMetricAttributes(values []attribute.KeyValue, want map[string]string) bool {
if len(values) != len(want) {
return false
}
for _, value := range values {
if want[string(value.Key)] != value.Value.AsString() {
return false
}
}
return true
}
var (
_ ports.AuthDirectoryStore = stubAuthDirectoryStore{}
_ ports.Clock = fixedClock{}
_ ports.IDGenerator = fixedIDGenerator{}
_ ports.IDGenerator = (*sequenceIDGenerator)(nil)
_ ports.RaceNamePolicy = stubRaceNamePolicy{}
_ ports.ProfileChangedPublisher = (*recordingAuthDomainEventPublisher)(nil)
_ ports.SettingsChangedPublisher = (*recordingAuthDomainEventPublisher)(nil)
_ ports.EntitlementChangedPublisher = (*recordingAuthDomainEventPublisher)(nil)
)