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,705 @@
package policysvc
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/shared"
"github.com/stretchr/testify/require"
)
func TestApplySanctionServiceExecuteBuildsActiveRecord(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
service, err := NewApplySanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{sanctionRecordID: policy.SanctionRecordID("sanction-1")},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), ApplySanctionInput{
UserID: userID.String(),
SanctionCode: string(policy.SanctionCodeLoginBlock),
Scope: "auth",
ReasonCode: "policy_blocked",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
AppliedAt: now.Add(-time.Minute).Format(time.RFC3339Nano),
ExpiresAt: now.Add(time.Hour).Format(time.RFC3339Nano),
})
require.NoError(t, err)
require.Equal(t, userID.String(), result.UserID)
require.Len(t, result.ActiveSanctions, 1)
require.Equal(t, string(policy.SanctionCodeLoginBlock), result.ActiveSanctions[0].SanctionCode)
records, err := sanctionStore.ListByUserID(context.Background(), userID)
require.NoError(t, err)
require.Len(t, records, 1)
require.Equal(t, policy.SanctionRecordID("sanction-1"), records[0].RecordID)
}
func TestApplySanctionServiceExecuteRejectsExpiredSanction(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
service, err := NewApplySanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{sanctionRecordID: policy.SanctionRecordID("sanction-1")},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), ApplySanctionInput{
UserID: userID.String(),
SanctionCode: string(policy.SanctionCodeLoginBlock),
Scope: "auth",
ReasonCode: "policy_blocked",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
AppliedAt: now.Add(-2 * time.Hour).Format(time.RFC3339Nano),
ExpiresAt: now.Add(-time.Minute).Format(time.RFC3339Nano),
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeInvalidRequest, shared.CodeOf(err))
}
func TestApplySanctionServiceExecuteReturnsConflictWhenActiveSanctionExists(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
existing := policy.SanctionRecord{
RecordID: policy.SanctionRecordID("sanction-existing"),
UserID: userID,
SanctionCode: policy.SanctionCodeLoginBlock,
Scope: common.Scope("auth"),
ReasonCode: common.ReasonCode("policy_blocked"),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
AppliedAt: now.Add(-time.Hour),
}
require.NoError(t, sanctionStore.Create(context.Background(), existing))
service, err := NewApplySanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
newFakeLimitStore(),
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: newFakeLimitStore()},
fixedClock{now: now},
fixedIDGenerator{sanctionRecordID: policy.SanctionRecordID("sanction-1")},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), ApplySanctionInput{
UserID: userID.String(),
SanctionCode: string(policy.SanctionCodeLoginBlock),
Scope: "auth",
ReasonCode: "policy_blocked",
Actor: ActorInput{Type: "admin", ID: "admin-2"},
AppliedAt: now.Add(-time.Minute).Format(time.RFC3339Nano),
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeConflict, shared.CodeOf(err))
}
func TestApplySanctionServiceExecuteReturnsNotFoundForUnknownUser(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
service, err := NewApplySanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{}},
newFakeSanctionStore(),
newFakeLimitStore(),
&fakePolicyLifecycleStore{sanctions: newFakeSanctionStore(), limits: newFakeLimitStore()},
fixedClock{now: now},
fixedIDGenerator{sanctionRecordID: policy.SanctionRecordID("sanction-1")},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), ApplySanctionInput{
UserID: "user-missing",
SanctionCode: string(policy.SanctionCodeLoginBlock),
Scope: "auth",
ReasonCode: "policy_blocked",
Actor: ActorInput{Type: "admin"},
AppliedAt: now.Format(time.RFC3339Nano),
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeSubjectNotFound, shared.CodeOf(err))
}
func TestRemoveSanctionServiceExecuteIsIdempotentWhenMissing(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
service, err := NewRemoveSanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), RemoveSanctionInput{
UserID: userID.String(),
SanctionCode: string(policy.SanctionCodeLoginBlock),
ReasonCode: "manual_remove",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
})
require.NoError(t, err)
require.Equal(t, userID.String(), result.UserID)
require.Empty(t, result.ActiveSanctions)
}
func TestRemoveSanctionServiceExecuteTreatsConcurrentRemovalAsSuccess(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
record := policy.SanctionRecord{
RecordID: policy.SanctionRecordID("sanction-1"),
UserID: userID,
SanctionCode: policy.SanctionCodeLoginBlock,
Scope: common.Scope("auth"),
ReasonCode: common.ReasonCode("policy_blocked"),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
AppliedAt: now.Add(-time.Hour),
}
require.NoError(t, sanctionStore.Create(context.Background(), record))
lifecycle := &fakePolicyLifecycleStore{
sanctions: sanctionStore,
limits: limitStore,
removeSanctionHook: func(input ports.RemoveSanctionInput) error {
updated := input.ExpectedActiveRecord
removedAt := now.Add(-time.Minute)
updated.RemovedAt = &removedAt
updated.RemovedBy = common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-2")}
updated.RemovedReasonCode = common.ReasonCode("manual_remove")
if err := sanctionStore.Update(context.Background(), updated); err != nil {
return err
}
return ports.ErrConflict
},
}
service, err := NewRemoveSanctionService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
lifecycle,
fixedClock{now: now},
fixedIDGenerator{},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), RemoveSanctionInput{
UserID: userID.String(),
SanctionCode: string(policy.SanctionCodeLoginBlock),
ReasonCode: "manual_remove",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
})
require.NoError(t, err)
require.Empty(t, result.ActiveSanctions)
}
func TestSetLimitServiceExecuteReplacesActiveLimit(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
current := policy.LimitRecord{
RecordID: policy.LimitRecordID("limit-existing"),
UserID: userID,
LimitCode: policy.LimitCodeMaxOwnedPrivateGames,
Value: 3,
ReasonCode: common.ReasonCode("manual_override"),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
AppliedAt: now.Add(-time.Hour),
}
require.NoError(t, limitStore.Create(context.Background(), current))
service, err := NewSetLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{limitRecordID: policy.LimitRecordID("limit-new")},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), SetLimitInput{
UserID: userID.String(),
LimitCode: string(policy.LimitCodeMaxOwnedPrivateGames),
Value: 5,
ReasonCode: "manual_override",
Actor: ActorInput{Type: "admin", ID: "admin-2"},
AppliedAt: now.Format(time.RFC3339Nano),
})
require.NoError(t, err)
require.Len(t, result.ActiveLimits, 1)
require.Equal(t, 5, result.ActiveLimits[0].Value)
storedCurrent, err := limitStore.GetByRecordID(context.Background(), current.RecordID)
require.NoError(t, err)
require.NotNil(t, storedCurrent.RemovedAt)
require.True(t, storedCurrent.RemovedAt.Equal(now))
}
func TestSetLimitServiceExecuteRejectsRetroactiveReplacement(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
limitStore := newFakeLimitStore()
current := policy.LimitRecord{
RecordID: policy.LimitRecordID("limit-existing"),
UserID: userID,
LimitCode: policy.LimitCodeMaxOwnedPrivateGames,
Value: 3,
ReasonCode: common.ReasonCode("manual_override"),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
AppliedAt: now.Add(-time.Hour),
}
require.NoError(t, limitStore.Create(context.Background(), current))
service, err := NewSetLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
newFakeSanctionStore(),
limitStore,
&fakePolicyLifecycleStore{sanctions: newFakeSanctionStore(), limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{limitRecordID: policy.LimitRecordID("limit-new")},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), SetLimitInput{
UserID: userID.String(),
LimitCode: string(policy.LimitCodeMaxOwnedPrivateGames),
Value: 5,
ReasonCode: "manual_override",
Actor: ActorInput{Type: "admin", ID: "admin-2"},
AppliedAt: now.Add(-2 * time.Hour).Format(time.RFC3339Nano),
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeInvalidRequest, shared.CodeOf(err))
}
func TestSetLimitServiceExecuteRejectsRetiredLimitCodes(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
tests := []string{
string(policy.LimitCodeMaxActivePrivateGames),
string(policy.LimitCodeMaxPendingPrivateJoinRequests),
string(policy.LimitCodeMaxPendingPrivateInvitesSent),
}
for _, limitCode := range tests {
limitCode := limitCode
t.Run(limitCode, func(t *testing.T) {
t.Parallel()
service, err := NewSetLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
newFakeSanctionStore(),
newFakeLimitStore(),
&fakePolicyLifecycleStore{sanctions: newFakeSanctionStore(), limits: newFakeLimitStore()},
fixedClock{now: now},
fixedIDGenerator{limitRecordID: policy.LimitRecordID("limit-new")},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), SetLimitInput{
UserID: userID.String(),
LimitCode: limitCode,
Value: 5,
ReasonCode: "manual_override",
Actor: ActorInput{Type: "admin", ID: "admin-2"},
AppliedAt: now.Format(time.RFC3339Nano),
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeInvalidRequest, shared.CodeOf(err))
})
}
}
func TestSetLimitServiceExecuteIgnoresRetiredRecordsDuringReload(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
limitStore := newFakeLimitStore()
require.NoError(t, limitStore.Create(context.Background(), policy.LimitRecord{
RecordID: policy.LimitRecordID("limit-legacy"),
UserID: userID,
LimitCode: policy.LimitCodeMaxActivePrivateGames,
Value: 9,
ReasonCode: common.ReasonCode("legacy_override"),
Actor: common.ActorRef{Type: common.ActorType("admin"), ID: common.ActorID("admin-1")},
AppliedAt: now.Add(-time.Hour),
}))
service, err := NewSetLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
newFakeSanctionStore(),
limitStore,
&fakePolicyLifecycleStore{sanctions: newFakeSanctionStore(), limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{limitRecordID: policy.LimitRecordID("limit-new")},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), SetLimitInput{
UserID: userID.String(),
LimitCode: string(policy.LimitCodeMaxOwnedPrivateGames),
Value: 5,
ReasonCode: "manual_override",
Actor: ActorInput{Type: "admin", ID: "admin-2"},
AppliedAt: now.Format(time.RFC3339Nano),
})
require.NoError(t, err)
require.Len(t, result.ActiveLimits, 1)
require.Equal(t, string(policy.LimitCodeMaxOwnedPrivateGames), result.ActiveLimits[0].LimitCode)
}
func TestRemoveLimitServiceExecuteIsIdempotentWhenMissing(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
service, err := NewRemoveLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{},
)
require.NoError(t, err)
result, err := service.Execute(context.Background(), RemoveLimitInput{
UserID: userID.String(),
LimitCode: string(policy.LimitCodeMaxOwnedPrivateGames),
ReasonCode: "manual_remove",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
})
require.NoError(t, err)
require.Empty(t, result.ActiveLimits)
}
func TestRemoveLimitServiceExecuteRejectsRetiredLimitCode(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
service, err := NewRemoveLimitService(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
newFakeSanctionStore(),
newFakeLimitStore(),
&fakePolicyLifecycleStore{sanctions: newFakeSanctionStore(), limits: newFakeLimitStore()},
fixedClock{now: now},
fixedIDGenerator{},
)
require.NoError(t, err)
_, err = service.Execute(context.Background(), RemoveLimitInput{
UserID: userID.String(),
LimitCode: string(policy.LimitCodeMaxPendingPrivateJoinRequests),
ReasonCode: "manual_remove",
Actor: ActorInput{Type: "admin", ID: "admin-1"},
})
require.Error(t, err)
require.Equal(t, shared.ErrorCodeInvalidRequest, shared.CodeOf(err))
}
type fakeAccountStore struct {
existsByUserID map[common.UserID]bool
}
func (store fakeAccountStore) Create(context.Context, ports.CreateAccountInput) error {
return nil
}
func (store fakeAccountStore) GetByUserID(context.Context, common.UserID) (account.UserAccount, error) {
return account.UserAccount{}, ports.ErrNotFound
}
func (store fakeAccountStore) GetByEmail(context.Context, common.Email) (account.UserAccount, error) {
return account.UserAccount{}, ports.ErrNotFound
}
func (store fakeAccountStore) GetByRaceName(context.Context, common.RaceName) (account.UserAccount, error) {
return account.UserAccount{}, ports.ErrNotFound
}
func (store fakeAccountStore) ExistsByUserID(_ context.Context, userID common.UserID) (bool, error) {
return store.existsByUserID[userID], nil
}
func (store fakeAccountStore) RenameRaceName(context.Context, ports.RenameRaceNameInput) error {
return nil
}
func (store fakeAccountStore) Update(context.Context, account.UserAccount) error {
return nil
}
type fakeSanctionStore struct {
byUserID map[common.UserID][]policy.SanctionRecord
byRecordID map[policy.SanctionRecordID]policy.SanctionRecord
}
func newFakeSanctionStore() *fakeSanctionStore {
return &fakeSanctionStore{
byUserID: make(map[common.UserID][]policy.SanctionRecord),
byRecordID: make(map[policy.SanctionRecordID]policy.SanctionRecord),
}
}
func (store *fakeSanctionStore) Create(_ context.Context, record policy.SanctionRecord) error {
if err := record.Validate(); err != nil {
return err
}
if _, exists := store.byRecordID[record.RecordID]; exists {
return ports.ErrConflict
}
store.byRecordID[record.RecordID] = record
store.byUserID[record.UserID] = append(store.byUserID[record.UserID], record)
return nil
}
func (store *fakeSanctionStore) GetByRecordID(_ context.Context, recordID policy.SanctionRecordID) (policy.SanctionRecord, error) {
record, ok := store.byRecordID[recordID]
if !ok {
return policy.SanctionRecord{}, ports.ErrNotFound
}
return record, nil
}
func (store *fakeSanctionStore) ListByUserID(_ context.Context, userID common.UserID) ([]policy.SanctionRecord, error) {
records := store.byUserID[userID]
cloned := make([]policy.SanctionRecord, len(records))
copy(cloned, records)
return cloned, nil
}
func (store *fakeSanctionStore) Update(_ context.Context, record policy.SanctionRecord) error {
if err := record.Validate(); err != nil {
return err
}
if _, exists := store.byRecordID[record.RecordID]; !exists {
return ports.ErrNotFound
}
store.byRecordID[record.RecordID] = record
records := store.byUserID[record.UserID]
for index := range records {
if records[index].RecordID == record.RecordID {
records[index] = record
store.byUserID[record.UserID] = records
return nil
}
}
return ports.ErrNotFound
}
type fakeLimitStore struct {
byUserID map[common.UserID][]policy.LimitRecord
byRecordID map[policy.LimitRecordID]policy.LimitRecord
}
func newFakeLimitStore() *fakeLimitStore {
return &fakeLimitStore{
byUserID: make(map[common.UserID][]policy.LimitRecord),
byRecordID: make(map[policy.LimitRecordID]policy.LimitRecord),
}
}
func (store *fakeLimitStore) Create(_ context.Context, record policy.LimitRecord) error {
if err := record.Validate(); err != nil {
return err
}
if _, exists := store.byRecordID[record.RecordID]; exists {
return ports.ErrConflict
}
store.byRecordID[record.RecordID] = record
store.byUserID[record.UserID] = append(store.byUserID[record.UserID], record)
return nil
}
func (store *fakeLimitStore) GetByRecordID(_ context.Context, recordID policy.LimitRecordID) (policy.LimitRecord, error) {
record, ok := store.byRecordID[recordID]
if !ok {
return policy.LimitRecord{}, ports.ErrNotFound
}
return record, nil
}
func (store *fakeLimitStore) ListByUserID(_ context.Context, userID common.UserID) ([]policy.LimitRecord, error) {
records := store.byUserID[userID]
cloned := make([]policy.LimitRecord, len(records))
copy(cloned, records)
return cloned, nil
}
func (store *fakeLimitStore) Update(_ context.Context, record policy.LimitRecord) error {
if err := record.Validate(); err != nil {
return err
}
if _, exists := store.byRecordID[record.RecordID]; !exists {
return ports.ErrNotFound
}
store.byRecordID[record.RecordID] = record
records := store.byUserID[record.UserID]
for index := range records {
if records[index].RecordID == record.RecordID {
records[index] = record
store.byUserID[record.UserID] = records
return nil
}
}
return ports.ErrNotFound
}
type fakePolicyLifecycleStore struct {
sanctions *fakeSanctionStore
limits *fakeLimitStore
applySanctionHook func(input ports.ApplySanctionInput) error
removeSanctionHook func(input ports.RemoveSanctionInput) error
setLimitHook func(input ports.SetLimitInput) error
removeLimitHook func(input ports.RemoveLimitInput) error
}
func (store *fakePolicyLifecycleStore) ApplySanction(ctx context.Context, input ports.ApplySanctionInput) error {
if store.applySanctionHook != nil {
return store.applySanctionHook(input)
}
records, err := store.sanctions.ListByUserID(ctx, input.NewRecord.UserID)
if err != nil {
return err
}
active, err := policy.ActiveSanctionsAt(records, input.NewRecord.AppliedAt)
if err != nil {
return err
}
for _, record := range active {
if record.SanctionCode == input.NewRecord.SanctionCode {
return ports.ErrConflict
}
}
return store.sanctions.Create(ctx, input.NewRecord)
}
func (store *fakePolicyLifecycleStore) RemoveSanction(ctx context.Context, input ports.RemoveSanctionInput) error {
if store.removeSanctionHook != nil {
return store.removeSanctionHook(input)
}
return store.sanctions.Update(ctx, input.UpdatedRecord)
}
func (store *fakePolicyLifecycleStore) SetLimit(ctx context.Context, input ports.SetLimitInput) error {
if store.setLimitHook != nil {
return store.setLimitHook(input)
}
if input.ExpectedActiveRecord != nil {
if err := store.limits.Update(ctx, *input.UpdatedActiveRecord); err != nil {
return err
}
}
return store.limits.Create(ctx, input.NewRecord)
}
func (store *fakePolicyLifecycleStore) RemoveLimit(ctx context.Context, input ports.RemoveLimitInput) error {
if store.removeLimitHook != nil {
return store.removeLimitHook(input)
}
return store.limits.Update(ctx, input.UpdatedRecord)
}
type fixedClock struct {
now time.Time
}
func (clock fixedClock) Now() time.Time {
return clock.now
}
type fixedIDGenerator struct {
sanctionRecordID policy.SanctionRecordID
limitRecordID policy.LimitRecordID
}
func (generator fixedIDGenerator) NewUserID() (common.UserID, error) {
return "", nil
}
func (generator fixedIDGenerator) NewInitialRaceName() (common.RaceName, error) {
return "", nil
}
func (generator fixedIDGenerator) NewEntitlementRecordID() (entitlement.EntitlementRecordID, error) {
return "", nil
}
func (generator fixedIDGenerator) NewSanctionRecordID() (policy.SanctionRecordID, error) {
return generator.sanctionRecordID, nil
}
func (generator fixedIDGenerator) NewLimitRecordID() (policy.LimitRecordID, error) {
return generator.limitRecordID, nil
}
var (
_ ports.UserAccountStore = fakeAccountStore{}
_ ports.SanctionStore = (*fakeSanctionStore)(nil)
_ ports.LimitStore = (*fakeLimitStore)(nil)
_ ports.PolicyLifecycleStore = (*fakePolicyLifecycleStore)(nil)
_ ports.Clock = fixedClock{}
_ ports.IDGenerator = fixedIDGenerator{}
)