Files
galaxy-game/user/internal/service/policysvc/observability_test.go
T
2026-04-10 19:05:02 +02:00

179 lines
5.4 KiB
Go

package policysvc
import (
"context"
"testing"
"time"
"galaxy/user/internal/domain/common"
"galaxy/user/internal/domain/policy"
"galaxy/user/internal/ports"
"github.com/stretchr/testify/require"
)
func TestApplySanctionServiceExecutePublishesEvent(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
publisher := &recordingPolicyPublisher{}
service, err := NewApplySanctionServiceWithObservability(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{sanctionRecordID: policy.SanctionRecordID("sanction-1")},
nil,
nil,
publisher,
)
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(-time.Minute).Format(time.RFC3339Nano),
ExpiresAt: now.Add(time.Hour).Format(time.RFC3339Nano),
})
require.NoError(t, err)
require.Len(t, publisher.sanctionEvents, 1)
require.Equal(t, ports.SanctionChangedOperationApplied, publisher.sanctionEvents[0].Operation)
require.Equal(t, common.Source("admin_internal_api"), publisher.sanctionEvents[0].Source)
}
func TestRemoveSanctionServiceExecuteMissingDoesNotPublishEvent(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
publisher := &recordingPolicyPublisher{}
service, err := NewRemoveSanctionServiceWithObservability(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{},
nil,
nil,
publisher,
)
require.NoError(t, err)
_, 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, publisher.sanctionEvents)
}
func TestSetLimitServiceExecutePublishesEvent(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
publisher := &recordingPolicyPublisher{}
service, err := NewSetLimitServiceWithObservability(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{limitRecordID: policy.LimitRecordID("limit-1")},
nil,
nil,
publisher,
)
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-1"},
AppliedAt: now.Add(-time.Minute).Format(time.RFC3339Nano),
ExpiresAt: now.Add(time.Hour).Format(time.RFC3339Nano),
})
require.NoError(t, err)
require.Len(t, publisher.limitEvents, 1)
require.Equal(t, ports.LimitChangedOperationSet, publisher.limitEvents[0].Operation)
require.NotNil(t, publisher.limitEvents[0].Value)
require.Equal(t, 5, *publisher.limitEvents[0].Value)
}
func TestRemoveLimitServiceExecuteMissingDoesNotPublishEvent(t *testing.T) {
t.Parallel()
now := time.Unix(1_775_240_000, 0).UTC()
userID := common.UserID("user-123")
sanctionStore := newFakeSanctionStore()
limitStore := newFakeLimitStore()
publisher := &recordingPolicyPublisher{}
service, err := NewRemoveLimitServiceWithObservability(
fakeAccountStore{existsByUserID: map[common.UserID]bool{userID: true}},
sanctionStore,
limitStore,
&fakePolicyLifecycleStore{sanctions: sanctionStore, limits: limitStore},
fixedClock{now: now},
fixedIDGenerator{},
nil,
nil,
publisher,
)
require.NoError(t, err)
_, 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, publisher.limitEvents)
}
type recordingPolicyPublisher struct {
sanctionEvents []ports.SanctionChangedEvent
limitEvents []ports.LimitChangedEvent
}
func (publisher *recordingPolicyPublisher) PublishSanctionChanged(_ context.Context, event ports.SanctionChangedEvent) error {
if err := event.Validate(); err != nil {
return err
}
publisher.sanctionEvents = append(publisher.sanctionEvents, event)
return nil
}
func (publisher *recordingPolicyPublisher) PublishLimitChanged(_ context.Context, event ports.LimitChangedEvent) error {
if err := event.Validate(); err != nil {
return err
}
publisher.limitEvents = append(publisher.limitEvents, event)
return nil
}
var (
_ ports.SanctionChangedPublisher = (*recordingPolicyPublisher)(nil)
_ ports.LimitChangedPublisher = (*recordingPolicyPublisher)(nil)
)