718 lines
24 KiB
Go
718 lines
24 KiB
Go
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)
|
|
)
|