677 lines
20 KiB
Go
677 lines
20 KiB
Go
package selfservice
|
|
|
|
import (
|
|
"context"
|
|
"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/entitlementsvc"
|
|
"galaxy/user/internal/service/shared"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAccountGetterExecuteReturnsAggregate(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
accountStore := newFakeAccountStore(validUserAccount())
|
|
snapshotStore := &fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now),
|
|
},
|
|
}
|
|
sanctionStore := fakeSanctionStore{
|
|
byUserID: map[common.UserID][]policy.SanctionRecord{
|
|
common.UserID("user-123"): {
|
|
validActiveSanction(common.UserID("user-123"), policy.SanctionCodeLoginBlock, now.Add(-time.Hour)),
|
|
expiredSanction(common.UserID("user-123"), policy.SanctionCodeGameJoinBlock, now.Add(-2*time.Hour)),
|
|
},
|
|
},
|
|
}
|
|
limitStore := fakeLimitStore{
|
|
byUserID: map[common.UserID][]policy.LimitRecord{
|
|
common.UserID("user-123"): {
|
|
validActiveLimit(common.UserID("user-123"), policy.LimitCodeMaxOwnedPrivateGames, 3, now.Add(-time.Hour)),
|
|
validActiveLimit(common.UserID("user-123"), policy.LimitCodeMaxActivePrivateGames, 1, now.Add(-2*time.Hour)),
|
|
},
|
|
},
|
|
}
|
|
|
|
service, err := NewAccountGetter(accountStore, snapshotStore, sanctionStore, limitStore, fixedClock{now: now})
|
|
require.NoError(t, err)
|
|
|
|
result, err := service.Execute(context.Background(), GetMyAccountInput{UserID: " user-123 "})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "user-123", result.Account.UserID)
|
|
require.Equal(t, "DE", result.Account.DeclaredCountry)
|
|
require.Len(t, result.Account.ActiveSanctions, 1)
|
|
require.Equal(t, string(policy.SanctionCodeLoginBlock), result.Account.ActiveSanctions[0].SanctionCode)
|
|
require.Len(t, result.Account.ActiveLimits, 1)
|
|
require.Equal(t, string(policy.LimitCodeMaxOwnedPrivateGames), result.Account.ActiveLimits[0].LimitCode)
|
|
}
|
|
|
|
func TestAccountGetterExecuteUnknownUserReturnsNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
service, err := NewAccountGetter(
|
|
newFakeAccountStore(),
|
|
&fakeEntitlementSnapshotStore{},
|
|
fakeSanctionStore{},
|
|
fakeLimitStore{},
|
|
fixedClock{now: time.Unix(1_775_240_500, 0).UTC()},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Execute(context.Background(), GetMyAccountInput{UserID: "user-missing"})
|
|
require.Error(t, err)
|
|
require.Equal(t, shared.ErrorCodeSubjectNotFound, shared.CodeOf(err))
|
|
}
|
|
|
|
func TestAccountGetterExecuteMissingSnapshotReturnsInternalError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
service, err := NewAccountGetter(
|
|
newFakeAccountStore(validUserAccount()),
|
|
&fakeEntitlementSnapshotStore{},
|
|
fakeSanctionStore{},
|
|
fakeLimitStore{},
|
|
fixedClock{now: time.Unix(1_775_240_500, 0).UTC()},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Execute(context.Background(), GetMyAccountInput{UserID: "user-123"})
|
|
require.Error(t, err)
|
|
require.Equal(t, shared.ErrorCodeInternalError, shared.CodeOf(err))
|
|
}
|
|
|
|
func TestAccountGetterExecuteRepairsExpiredPaidSnapshot(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
expiredAt := now.Add(-time.Hour)
|
|
snapshotStore := &fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): {
|
|
UserID: common.UserID("user-123"),
|
|
PlanCode: entitlement.PlanCodePaidMonthly,
|
|
IsPaid: true,
|
|
StartsAt: now.Add(-30 * 24 * time.Hour),
|
|
EndsAt: timePointer(expiredAt),
|
|
Source: common.Source("admin"),
|
|
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
|
|
ReasonCode: common.ReasonCode("manual_grant"),
|
|
UpdatedAt: expiredAt,
|
|
},
|
|
},
|
|
}
|
|
reader, err := entitlementsvc.NewReader(
|
|
snapshotStore,
|
|
&fakeEntitlementLifecycleStore{snapshotStore: snapshotStore},
|
|
fixedClock{now: now},
|
|
readerIDGenerator{recordID: entitlement.EntitlementRecordID("entitlement-free-after-expiry")},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
service, err := NewAccountGetter(
|
|
newFakeAccountStore(validUserAccount()),
|
|
reader,
|
|
fakeSanctionStore{},
|
|
fakeLimitStore{},
|
|
fixedClock{now: now},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
result, err := service.Execute(context.Background(), GetMyAccountInput{UserID: "user-123"})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "free", result.Account.Entitlement.PlanCode)
|
|
require.False(t, result.Account.Entitlement.IsPaid)
|
|
require.Equal(t, expiredAt, result.Account.Entitlement.StartsAt)
|
|
}
|
|
|
|
func TestProfileUpdaterExecuteBlockedBySanction(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
accountStore := newFakeAccountStore(validUserAccount())
|
|
service, err := NewProfileUpdater(
|
|
accountStore,
|
|
&fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now),
|
|
},
|
|
},
|
|
fakeSanctionStore{
|
|
byUserID: map[common.UserID][]policy.SanctionRecord{
|
|
common.UserID("user-123"): {
|
|
validActiveSanction(common.UserID("user-123"), policy.SanctionCodeProfileUpdateBlock, now.Add(-time.Minute)),
|
|
},
|
|
},
|
|
},
|
|
fakeLimitStore{},
|
|
fixedClock{now: now},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Execute(context.Background(), UpdateMyProfileInput{
|
|
UserID: "user-123",
|
|
DisplayName: "NovaPrime",
|
|
})
|
|
require.Error(t, err)
|
|
require.Equal(t, shared.ErrorCodeConflict, shared.CodeOf(err))
|
|
require.Equal(t, 0, accountStore.updateCalls)
|
|
}
|
|
|
|
func TestProfileUpdaterExecuteDisplayNameUpdates(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputDisplay string
|
|
updateErr error
|
|
wantCode string
|
|
wantDisplay string
|
|
wantUpdateCalls int
|
|
}{
|
|
{
|
|
name: "set display name",
|
|
inputDisplay: "NovaPrime",
|
|
wantDisplay: "NovaPrime",
|
|
wantUpdateCalls: 1,
|
|
},
|
|
{
|
|
name: "trims input",
|
|
inputDisplay: " NovaPrime ",
|
|
wantDisplay: "NovaPrime",
|
|
wantUpdateCalls: 1,
|
|
},
|
|
{
|
|
name: "reset to empty",
|
|
inputDisplay: " ",
|
|
wantDisplay: "",
|
|
wantUpdateCalls: 0,
|
|
},
|
|
{
|
|
name: "invalid display name rejected",
|
|
inputDisplay: "Nova Prime",
|
|
wantCode: shared.ErrorCodeInvalidRequest,
|
|
wantDisplay: "",
|
|
wantUpdateCalls: 0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
accountStore := newFakeAccountStore(validUserAccount())
|
|
accountStore.updateErr = tt.updateErr
|
|
service, err := NewProfileUpdater(
|
|
accountStore,
|
|
&fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now),
|
|
},
|
|
},
|
|
fakeSanctionStore{},
|
|
fakeLimitStore{},
|
|
fixedClock{now: now},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
result, err := service.Execute(context.Background(), UpdateMyProfileInput{
|
|
UserID: "user-123",
|
|
DisplayName: tt.inputDisplay,
|
|
})
|
|
if tt.wantCode != "" {
|
|
require.Error(t, err)
|
|
require.Equal(t, tt.wantCode, shared.CodeOf(err))
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
require.Equal(t, tt.wantUpdateCalls, accountStore.updateCalls)
|
|
|
|
storedAccount, err := accountStore.GetByUserID(context.Background(), common.UserID("user-123"))
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.wantDisplay, storedAccount.DisplayName.String())
|
|
if tt.wantCode == "" {
|
|
require.Equal(t, tt.wantDisplay, result.Account.DisplayName)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSettingsUpdaterExecuteBlockedBySanction(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
accountStore := newFakeAccountStore(validUserAccount())
|
|
service, err := NewSettingsUpdater(
|
|
accountStore,
|
|
&fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now),
|
|
},
|
|
},
|
|
fakeSanctionStore{
|
|
byUserID: map[common.UserID][]policy.SanctionRecord{
|
|
common.UserID("user-123"): {
|
|
validActiveSanction(common.UserID("user-123"), policy.SanctionCodeProfileUpdateBlock, now.Add(-time.Minute)),
|
|
},
|
|
},
|
|
},
|
|
fakeLimitStore{},
|
|
fixedClock{now: now},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Execute(context.Background(), UpdateMySettingsInput{
|
|
UserID: "user-123",
|
|
PreferredLanguage: "en-US",
|
|
TimeZone: "UTC",
|
|
})
|
|
require.Error(t, err)
|
|
require.Equal(t, shared.ErrorCodeConflict, shared.CodeOf(err))
|
|
require.Equal(t, 0, accountStore.updateCalls)
|
|
}
|
|
|
|
func TestSettingsUpdaterExecuteCanonicalizedNoOpAndInvalidInputs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
accountRecord account.UserAccount
|
|
inputLanguage string
|
|
inputTimeZone string
|
|
wantCode string
|
|
wantLanguage string
|
|
wantTimeZone string
|
|
wantUpdateCalls int
|
|
}{
|
|
{
|
|
name: "canonicalized success",
|
|
accountRecord: validUserAccount(),
|
|
inputLanguage: " en-us ",
|
|
inputTimeZone: " UTC ",
|
|
wantLanguage: "en-US",
|
|
wantTimeZone: "UTC",
|
|
wantUpdateCalls: 1,
|
|
},
|
|
{
|
|
name: "no-op",
|
|
accountRecord: account.UserAccount{
|
|
UserID: common.UserID("user-123"),
|
|
Email: common.Email("pilot@example.com"),
|
|
UserName: common.UserName("player-abcdefgh"),
|
|
PreferredLanguage: common.LanguageTag("en-US"),
|
|
TimeZone: common.TimeZoneName("UTC"),
|
|
DeclaredCountry: common.CountryCode("DE"),
|
|
CreatedAt: time.Unix(1_775_240_000, 0).UTC(),
|
|
UpdatedAt: time.Unix(1_775_240_000, 0).UTC(),
|
|
},
|
|
inputLanguage: "en-us",
|
|
inputTimeZone: " UTC ",
|
|
wantLanguage: "en-US",
|
|
wantTimeZone: "UTC",
|
|
wantUpdateCalls: 0,
|
|
},
|
|
{
|
|
name: "invalid preferred language",
|
|
accountRecord: validUserAccount(),
|
|
inputLanguage: "bad@@tag",
|
|
inputTimeZone: "UTC",
|
|
wantCode: shared.ErrorCodeInvalidRequest,
|
|
wantLanguage: "en",
|
|
wantTimeZone: "Europe/Kaliningrad",
|
|
},
|
|
{
|
|
name: "invalid time zone",
|
|
accountRecord: validUserAccount(),
|
|
inputLanguage: "en",
|
|
inputTimeZone: "Mars/Olympus",
|
|
wantCode: shared.ErrorCodeInvalidRequest,
|
|
wantLanguage: "en",
|
|
wantTimeZone: "Europe/Kaliningrad",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Unix(1_775_240_500, 0).UTC()
|
|
accountStore := newFakeAccountStore(tt.accountRecord)
|
|
service, err := NewSettingsUpdater(
|
|
accountStore,
|
|
&fakeEntitlementSnapshotStore{
|
|
byUserID: map[common.UserID]entitlement.CurrentSnapshot{
|
|
common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now),
|
|
},
|
|
},
|
|
fakeSanctionStore{},
|
|
fakeLimitStore{},
|
|
fixedClock{now: now},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
result, err := service.Execute(context.Background(), UpdateMySettingsInput{
|
|
UserID: "user-123",
|
|
PreferredLanguage: tt.inputLanguage,
|
|
TimeZone: tt.inputTimeZone,
|
|
})
|
|
if tt.wantCode != "" {
|
|
require.Error(t, err)
|
|
require.Equal(t, tt.wantCode, shared.CodeOf(err))
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
require.Equal(t, tt.wantUpdateCalls, accountStore.updateCalls)
|
|
|
|
storedAccount, err := accountStore.GetByUserID(context.Background(), common.UserID("user-123"))
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.wantLanguage, storedAccount.PreferredLanguage.String())
|
|
require.Equal(t, tt.wantTimeZone, storedAccount.TimeZone.String())
|
|
if tt.wantCode == "" {
|
|
require.Equal(t, tt.wantLanguage, result.Account.PreferredLanguage)
|
|
require.Equal(t, tt.wantTimeZone, result.Account.TimeZone)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type fakeAccountStore struct {
|
|
records map[common.UserID]account.UserAccount
|
|
updateErr error
|
|
updateCalls int
|
|
}
|
|
|
|
func newFakeAccountStore(records ...account.UserAccount) *fakeAccountStore {
|
|
byUserID := make(map[common.UserID]account.UserAccount, len(records))
|
|
for _, record := range records {
|
|
byUserID[record.UserID] = record
|
|
}
|
|
|
|
return &fakeAccountStore{records: byUserID}
|
|
}
|
|
|
|
func (store *fakeAccountStore) Create(_ context.Context, input ports.CreateAccountInput) error {
|
|
if input.Account.Validate() != nil {
|
|
return ports.ErrConflict
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (store *fakeAccountStore) GetByUserID(_ context.Context, userID common.UserID) (account.UserAccount, error) {
|
|
record, ok := store.records[userID]
|
|
if !ok {
|
|
return account.UserAccount{}, ports.ErrNotFound
|
|
}
|
|
|
|
return record, nil
|
|
}
|
|
|
|
func (store *fakeAccountStore) GetByEmail(_ context.Context, email common.Email) (account.UserAccount, error) {
|
|
for _, record := range store.records {
|
|
if record.Email == email {
|
|
return record, nil
|
|
}
|
|
}
|
|
|
|
return account.UserAccount{}, ports.ErrNotFound
|
|
}
|
|
|
|
func (store *fakeAccountStore) GetByUserName(_ context.Context, userName common.UserName) (account.UserAccount, error) {
|
|
for _, record := range store.records {
|
|
if record.UserName == userName {
|
|
return record, nil
|
|
}
|
|
}
|
|
|
|
return account.UserAccount{}, ports.ErrNotFound
|
|
}
|
|
|
|
func (store *fakeAccountStore) ExistsByUserID(_ context.Context, userID common.UserID) (bool, error) {
|
|
_, ok := store.records[userID]
|
|
return ok, nil
|
|
}
|
|
|
|
func (store *fakeAccountStore) Update(_ context.Context, record account.UserAccount) error {
|
|
store.updateCalls++
|
|
if store.updateErr != nil {
|
|
return store.updateErr
|
|
}
|
|
if _, ok := store.records[record.UserID]; !ok {
|
|
return ports.ErrNotFound
|
|
}
|
|
store.records[record.UserID] = record
|
|
return nil
|
|
}
|
|
|
|
type fakeEntitlementSnapshotStore struct {
|
|
byUserID map[common.UserID]entitlement.CurrentSnapshot
|
|
}
|
|
|
|
func (store *fakeEntitlementSnapshotStore) GetByUserID(_ context.Context, userID common.UserID) (entitlement.CurrentSnapshot, error) {
|
|
record, ok := store.byUserID[userID]
|
|
if !ok {
|
|
return entitlement.CurrentSnapshot{}, ports.ErrNotFound
|
|
}
|
|
|
|
return record, nil
|
|
}
|
|
|
|
func (store *fakeEntitlementSnapshotStore) Put(_ context.Context, record entitlement.CurrentSnapshot) error {
|
|
if store.byUserID != nil {
|
|
store.byUserID[record.UserID] = record
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type fakeEntitlementLifecycleStore struct {
|
|
snapshotStore *fakeEntitlementSnapshotStore
|
|
}
|
|
|
|
func (store *fakeEntitlementLifecycleStore) Grant(context.Context, ports.GrantEntitlementInput) error {
|
|
return nil
|
|
}
|
|
|
|
func (store *fakeEntitlementLifecycleStore) Extend(context.Context, ports.ExtendEntitlementInput) error {
|
|
return nil
|
|
}
|
|
|
|
func (store *fakeEntitlementLifecycleStore) Revoke(context.Context, ports.RevokeEntitlementInput) error {
|
|
return nil
|
|
}
|
|
|
|
func (store *fakeEntitlementLifecycleStore) RepairExpired(ctx context.Context, input ports.RepairExpiredEntitlementInput) error {
|
|
if store.snapshotStore != nil {
|
|
return store.snapshotStore.Put(ctx, input.NewSnapshot)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type readerIDGenerator struct {
|
|
recordID entitlement.EntitlementRecordID
|
|
sanctionRecordID policy.SanctionRecordID
|
|
limitRecordID policy.LimitRecordID
|
|
}
|
|
|
|
func (generator readerIDGenerator) NewUserID() (common.UserID, error) {
|
|
return "", nil
|
|
}
|
|
|
|
func (generator readerIDGenerator) NewUserName() (common.UserName, error) {
|
|
return "", nil
|
|
}
|
|
|
|
func (generator readerIDGenerator) NewEntitlementRecordID() (entitlement.EntitlementRecordID, error) {
|
|
return generator.recordID, nil
|
|
}
|
|
|
|
func (generator readerIDGenerator) NewSanctionRecordID() (policy.SanctionRecordID, error) {
|
|
return generator.sanctionRecordID, nil
|
|
}
|
|
|
|
func (generator readerIDGenerator) NewLimitRecordID() (policy.LimitRecordID, error) {
|
|
return generator.limitRecordID, nil
|
|
}
|
|
|
|
type fakeSanctionStore struct {
|
|
byUserID map[common.UserID][]policy.SanctionRecord
|
|
err error
|
|
}
|
|
|
|
func (store fakeSanctionStore) Create(context.Context, policy.SanctionRecord) error {
|
|
return nil
|
|
}
|
|
|
|
func (store fakeSanctionStore) GetByRecordID(context.Context, policy.SanctionRecordID) (policy.SanctionRecord, error) {
|
|
return policy.SanctionRecord{}, ports.ErrNotFound
|
|
}
|
|
|
|
func (store fakeSanctionStore) ListByUserID(_ context.Context, userID common.UserID) ([]policy.SanctionRecord, error) {
|
|
if store.err != nil {
|
|
return nil, store.err
|
|
}
|
|
|
|
records := store.byUserID[userID]
|
|
cloned := make([]policy.SanctionRecord, len(records))
|
|
copy(cloned, records)
|
|
return cloned, nil
|
|
}
|
|
|
|
func (store fakeSanctionStore) Update(context.Context, policy.SanctionRecord) error {
|
|
return nil
|
|
}
|
|
|
|
type fakeLimitStore struct {
|
|
byUserID map[common.UserID][]policy.LimitRecord
|
|
err error
|
|
}
|
|
|
|
func (store fakeLimitStore) Create(context.Context, policy.LimitRecord) error {
|
|
return nil
|
|
}
|
|
|
|
func (store fakeLimitStore) GetByRecordID(context.Context, policy.LimitRecordID) (policy.LimitRecord, error) {
|
|
return policy.LimitRecord{}, ports.ErrNotFound
|
|
}
|
|
|
|
func (store fakeLimitStore) ListByUserID(_ context.Context, userID common.UserID) ([]policy.LimitRecord, error) {
|
|
if store.err != nil {
|
|
return nil, store.err
|
|
}
|
|
|
|
records := store.byUserID[userID]
|
|
cloned := make([]policy.LimitRecord, len(records))
|
|
copy(cloned, records)
|
|
return cloned, nil
|
|
}
|
|
|
|
func (store fakeLimitStore) Update(context.Context, policy.LimitRecord) error {
|
|
return nil
|
|
}
|
|
|
|
type fixedClock struct {
|
|
now time.Time
|
|
}
|
|
|
|
func (clock fixedClock) Now() time.Time {
|
|
return clock.now
|
|
}
|
|
|
|
func validUserAccount() account.UserAccount {
|
|
createdAt := time.Unix(1_775_240_000, 0).UTC()
|
|
return account.UserAccount{
|
|
UserID: common.UserID("user-123"),
|
|
Email: common.Email("pilot@example.com"),
|
|
UserName: common.UserName("player-abcdefgh"),
|
|
PreferredLanguage: common.LanguageTag("en"),
|
|
TimeZone: common.TimeZoneName("Europe/Kaliningrad"),
|
|
DeclaredCountry: common.CountryCode("DE"),
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: createdAt,
|
|
}
|
|
}
|
|
|
|
func validEntitlementSnapshot(userID common.UserID, now time.Time) entitlement.CurrentSnapshot {
|
|
return entitlement.CurrentSnapshot{
|
|
UserID: userID,
|
|
PlanCode: entitlement.PlanCodeFree,
|
|
IsPaid: false,
|
|
StartsAt: now.Add(-time.Hour),
|
|
Source: common.Source("auth_registration"),
|
|
Actor: common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")},
|
|
ReasonCode: common.ReasonCode("initial_free_entitlement"),
|
|
UpdatedAt: now,
|
|
}
|
|
}
|
|
|
|
func validActiveSanction(userID common.UserID, code policy.SanctionCode, appliedAt time.Time) policy.SanctionRecord {
|
|
return policy.SanctionRecord{
|
|
RecordID: policy.SanctionRecordID("sanction-" + string(code)),
|
|
UserID: userID,
|
|
SanctionCode: code,
|
|
Scope: common.Scope("self_service"),
|
|
ReasonCode: common.ReasonCode("policy_enforced"),
|
|
Actor: common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")},
|
|
AppliedAt: appliedAt.UTC(),
|
|
}
|
|
}
|
|
|
|
func expiredSanction(userID common.UserID, code policy.SanctionCode, appliedAt time.Time) policy.SanctionRecord {
|
|
expiresAt := appliedAt.Add(30 * time.Minute)
|
|
record := validActiveSanction(userID, code, appliedAt)
|
|
record.RecordID = policy.SanctionRecordID(record.RecordID.String() + "-expired")
|
|
record.ExpiresAt = &expiresAt
|
|
return record
|
|
}
|
|
|
|
func validActiveLimit(userID common.UserID, code policy.LimitCode, value int, appliedAt time.Time) policy.LimitRecord {
|
|
return policy.LimitRecord{
|
|
RecordID: policy.LimitRecordID("limit-" + string(code)),
|
|
UserID: userID,
|
|
LimitCode: code,
|
|
Value: value,
|
|
ReasonCode: common.ReasonCode("policy_enforced"),
|
|
Actor: common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")},
|
|
AppliedAt: appliedAt.UTC(),
|
|
}
|
|
}
|
|
|
|
func removedLimit(userID common.UserID, code policy.LimitCode, value int, appliedAt time.Time) policy.LimitRecord {
|
|
removedAt := appliedAt.Add(30 * time.Minute)
|
|
record := validActiveLimit(userID, code, value, appliedAt)
|
|
record.RecordID = policy.LimitRecordID(record.RecordID.String() + "-removed")
|
|
record.RemovedAt = &removedAt
|
|
record.RemovedBy = common.ActorRef{Type: common.ActorType("service"), ID: common.ActorID("user-service")}
|
|
record.RemovedReasonCode = common.ReasonCode("policy_reset")
|
|
return record
|
|
}
|
|
|
|
func timePointer(value time.Time) *time.Time {
|
|
utcValue := value.UTC()
|
|
return &utcValue
|
|
}
|
|
|
|
var (
|
|
_ ports.UserAccountStore = (*fakeAccountStore)(nil)
|
|
_ ports.EntitlementSnapshotStore = (*fakeEntitlementSnapshotStore)(nil)
|
|
_ ports.EntitlementLifecycleStore = (*fakeEntitlementLifecycleStore)(nil)
|
|
_ ports.SanctionStore = fakeSanctionStore{}
|
|
_ ports.LimitStore = fakeLimitStore{}
|
|
_ ports.IDGenerator = readerIDGenerator{}
|
|
)
|