package selfservice import ( "context" "errors" "testing" "time" "galaxy/user/internal/domain/account" "galaxy/user/internal/domain/common" "galaxy/user/internal/domain/entitlement" "galaxy/user/internal/ports" "github.com/stretchr/testify/require" ) func TestProfileUpdaterExecutePublishesProfileChangedEvent(t *testing.T) { t.Parallel() now := time.Unix(1_775_240_500, 0).UTC() accountStore := newFakeAccountStore(validUserAccount()) publisher := &recordingSelfServicePublisher{} service, err := NewProfileUpdaterWithObservability( accountStore, &fakeEntitlementSnapshotStore{ byUserID: map[common.UserID]entitlement.CurrentSnapshot{ common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now), }, }, fakeSanctionStore{}, fakeLimitStore{}, fixedClock{now: now}, nil, nil, publisher, ) require.NoError(t, err) result, err := service.Execute(context.Background(), UpdateMyProfileInput{ UserID: "user-123", DisplayName: "NovaPrime", }) require.NoError(t, err) require.Equal(t, "NovaPrime", result.Account.DisplayName) require.Len(t, publisher.profileEvents, 1) require.Equal(t, ports.ProfileChangedOperationUpdated, publisher.profileEvents[0].Operation) require.Equal(t, common.Source("gateway_self_service"), publisher.profileEvents[0].Source) require.Equal(t, common.DisplayName("NovaPrime"), publisher.profileEvents[0].DisplayName) require.Equal(t, common.UserName("player-abcdefgh"), publisher.profileEvents[0].UserName) } func TestProfileUpdaterExecutePublisherFailureDoesNotRollbackCommit(t *testing.T) { t.Parallel() now := time.Unix(1_775_240_500, 0).UTC() accountStore := newFakeAccountStore(validUserAccount()) publisher := &recordingSelfServicePublisher{profileErr: errors.New("publisher unavailable")} service, err := NewProfileUpdaterWithObservability( accountStore, &fakeEntitlementSnapshotStore{ byUserID: map[common.UserID]entitlement.CurrentSnapshot{ common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now), }, }, fakeSanctionStore{}, fakeLimitStore{}, fixedClock{now: now}, nil, nil, publisher, ) require.NoError(t, err) result, err := service.Execute(context.Background(), UpdateMyProfileInput{ UserID: "user-123", DisplayName: "NovaPrime", }) require.NoError(t, err) require.Equal(t, "NovaPrime", result.Account.DisplayName) require.Len(t, publisher.profileEvents, 1) storedAccount, err := accountStore.GetByUserID(context.Background(), common.UserID("user-123")) require.NoError(t, err) require.Equal(t, common.DisplayName("NovaPrime"), storedAccount.DisplayName) } func TestSettingsUpdaterExecuteNoOpDoesNotPublishEvent(t *testing.T) { t.Parallel() now := time.Unix(1_775_240_500, 0).UTC() accountStore := newFakeAccountStore(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_100, 0).UTC(), }) publisher := &recordingSelfServicePublisher{} service, err := NewSettingsUpdaterWithObservability( accountStore, &fakeEntitlementSnapshotStore{ byUserID: map[common.UserID]entitlement.CurrentSnapshot{ common.UserID("user-123"): validEntitlementSnapshot(common.UserID("user-123"), now), }, }, fakeSanctionStore{}, fakeLimitStore{}, fixedClock{now: now}, nil, nil, publisher, ) require.NoError(t, err) result, err := service.Execute(context.Background(), UpdateMySettingsInput{ UserID: "user-123", PreferredLanguage: "en-us", TimeZone: " UTC ", }) require.NoError(t, err) require.Equal(t, "en-US", result.Account.PreferredLanguage) require.Equal(t, "UTC", result.Account.TimeZone) require.Empty(t, publisher.settingsEvents) } type recordingSelfServicePublisher struct { profileErr error settingsErr error profileEvents []ports.ProfileChangedEvent settingsEvents []ports.SettingsChangedEvent } func (publisher *recordingSelfServicePublisher) PublishProfileChanged(_ context.Context, event ports.ProfileChangedEvent) error { if err := event.Validate(); err != nil { return err } publisher.profileEvents = append(publisher.profileEvents, event) return publisher.profileErr } func (publisher *recordingSelfServicePublisher) PublishSettingsChanged(_ context.Context, event ports.SettingsChangedEvent) error { if err := event.Validate(); err != nil { return err } publisher.settingsEvents = append(publisher.settingsEvents, event) return publisher.settingsErr } var ( _ ports.ProfileChangedPublisher = (*recordingSelfServicePublisher)(nil) _ ports.SettingsChangedPublisher = (*recordingSelfServicePublisher)(nil) )