196 lines
7.6 KiB
Go
196 lines
7.6 KiB
Go
package agencyopening
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/protobuf/proto"
|
|
roomeventsv1 "hyapp.local/api/proto/events/room/v1"
|
|
roomv1 "hyapp.local/api/proto/room/v1"
|
|
walletv1 "hyapp.local/api/proto/wallet/v1"
|
|
"hyapp/pkg/appcode"
|
|
domain "hyapp/services/activity-service/internal/domain/agencyopening"
|
|
)
|
|
|
|
func TestEligibleRequiresHostCountGreaterThanConfigured(t *testing.T) {
|
|
cycle := domain.Cycle{MinHostCount: 10}
|
|
agency := domain.AgencySnapshot{Status: "active", HostCount: 10}
|
|
if ok, reason := eligible(cycle, agency, 1000); ok || reason != "host_count_not_enough" {
|
|
t.Fatalf("host_count equal to threshold must be rejected, got ok=%v reason=%q", ok, reason)
|
|
}
|
|
agency.HostCount = 11
|
|
if ok, reason := eligible(cycle, agency, 1000); !ok || reason != "" {
|
|
t.Fatalf("host_count above threshold must be eligible, got ok=%v reason=%q", ok, reason)
|
|
}
|
|
}
|
|
|
|
func TestGetStatusRejectsOwnerAlreadyAppliedInAnyCycle(t *testing.T) {
|
|
repo := &agencyOpeningFakeRepo{
|
|
currentCycle: domain.Cycle{CycleID: "current", Status: domain.StatusActive, StartMS: 1, EndMS: 10000, MinHostCount: 10},
|
|
hasCurrent: true,
|
|
application: domain.Application{
|
|
ApplicationID: "old-application",
|
|
CycleID: "previous",
|
|
AgencyOwnerUserID: 42,
|
|
Status: domain.ApplicationStatusApplied,
|
|
},
|
|
hasApplication: true,
|
|
}
|
|
svc := New(repo, nil, agencyOpeningFakeAgencySource{
|
|
snapshot: domain.AgencySnapshot{AgencyID: 7, OwnerUserID: 42, Status: "active", HostCount: 11},
|
|
ok: true,
|
|
}, nil)
|
|
svc.now = func() time.Time { return time.UnixMilli(5000).UTC() }
|
|
|
|
status, err := svc.GetStatus(appcode.WithContext(context.Background(), "lalu"), 42)
|
|
if err != nil {
|
|
t.Fatalf("GetStatus returned error: %v", err)
|
|
}
|
|
if !status.Joined || status.Eligible || status.IneligibleReason != "already_applied" {
|
|
t.Fatalf("expected already-applied owner to be blocked, got joined=%v eligible=%v reason=%q", status.Joined, status.Eligible, status.IneligibleReason)
|
|
}
|
|
if repo.ownerLookup != 42 {
|
|
t.Fatalf("expected repository lookup by owner_user_id, got %d", repo.ownerLookup)
|
|
}
|
|
}
|
|
|
|
func TestGetStatusRequiresAgencyOwner(t *testing.T) {
|
|
repo := &agencyOpeningFakeRepo{
|
|
currentCycle: domain.Cycle{CycleID: "current", Status: domain.StatusActive, StartMS: 1, EndMS: 10000, MinHostCount: 10},
|
|
hasCurrent: true,
|
|
}
|
|
svc := New(repo, nil, agencyOpeningFakeAgencySource{ok: false}, nil)
|
|
svc.now = func() time.Time { return time.UnixMilli(5000).UTC() }
|
|
|
|
status, err := svc.GetStatus(appcode.WithContext(context.Background(), "lalu"), 42)
|
|
if err != nil {
|
|
t.Fatalf("GetStatus returned error: %v", err)
|
|
}
|
|
if status.Joined || status.Eligible || status.IneligibleReason != "active_agency_owner_required" {
|
|
t.Fatalf("expected non-agency user to be blocked, got joined=%v eligible=%v reason=%q", status.Joined, status.Eligible, status.IneligibleReason)
|
|
}
|
|
}
|
|
|
|
func TestHandleRoomEventScoresApplicantRoomOwner(t *testing.T) {
|
|
repo := &agencyOpeningFakeRepo{consumeStatus: domain.EventStatusConsumed}
|
|
room := &agencyOpeningFakeRoomClient{ownerUserID: 42}
|
|
svc := New(repo, nil, nil, room)
|
|
svc.now = func() time.Time { return time.UnixMilli(8000).UTC() }
|
|
body, err := proto.Marshal(&roomeventsv1.RoomGiftSent{
|
|
SenderUserId: 9,
|
|
TargetUserId: 88,
|
|
GiftValue: 900,
|
|
CoinSpent: 1200,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("marshal gift: %v", err)
|
|
}
|
|
count, err := svc.HandleRoomEvent(context.Background(), &roomeventsv1.EventEnvelope{
|
|
EventId: "gift-event-1",
|
|
RoomId: "room-1",
|
|
EventType: "RoomGiftSent",
|
|
OccurredAtMs: 7000,
|
|
AppCode: "lalu",
|
|
Body: body,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("HandleRoomEvent returned error: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Fatalf("expected one consumed event, got %d", count)
|
|
}
|
|
if room.roomID != "room-1" {
|
|
t.Fatalf("expected room lookup by event room_id, got %q", room.roomID)
|
|
}
|
|
if repo.consumed.RoomOwnerUserID != 42 || repo.consumed.TargetUserID != 88 || repo.consumed.CoinSpent != 900 {
|
|
t.Fatalf("unexpected consumed event: %+v", repo.consumed)
|
|
}
|
|
}
|
|
|
|
type agencyOpeningFakeRepo struct {
|
|
currentCycle domain.Cycle
|
|
hasCurrent bool
|
|
application domain.Application
|
|
hasApplication bool
|
|
ownerLookup int64
|
|
consumeStatus string
|
|
consumed domain.GiftEvent
|
|
}
|
|
|
|
func (r *agencyOpeningFakeRepo) ListAgencyOpeningCycles(context.Context, domain.ListQuery) ([]domain.Cycle, int64, error) {
|
|
return nil, 0, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) GetAgencyOpeningCycle(context.Context, string) (domain.Cycle, error) {
|
|
return domain.Cycle{}, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) UpsertAgencyOpeningCycle(context.Context, domain.CycleCommand, int64) (domain.Cycle, bool, error) {
|
|
return domain.Cycle{}, false, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) SetAgencyOpeningCycleStatus(context.Context, string, string, int64, int64) (domain.Cycle, error) {
|
|
return domain.Cycle{}, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) FindCurrentAgencyOpeningCycle(context.Context, int64) (domain.Cycle, bool, error) {
|
|
return r.currentCycle, r.hasCurrent, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) GetAgencyOpeningApplicationByOwner(_ context.Context, ownerUserID int64) (domain.Application, bool, error) {
|
|
r.ownerLookup = ownerUserID
|
|
return r.application, r.hasApplication, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) CreateAgencyOpeningApplication(context.Context, domain.Cycle, domain.AgencySnapshot, int64) (domain.Application, bool, error) {
|
|
return domain.Application{}, false, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) ApproveAgencyOpeningApplication(context.Context, string, int64, int64) (domain.Application, error) {
|
|
return domain.Application{}, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) ListAgencyOpeningApplications(context.Context, domain.ApplicationQuery) ([]domain.Application, int64, error) {
|
|
return nil, 0, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) ConsumeAgencyOpeningGiftEvent(_ context.Context, event domain.GiftEvent, _ int64) (domain.EventResult, error) {
|
|
r.consumed = event
|
|
return domain.EventResult{EventID: event.EventID, Status: r.consumeStatus}, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) ClaimDueAgencyOpeningCycles(context.Context, string, int64, time.Duration, int32) ([]domain.Cycle, error) {
|
|
return nil, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) PrepareAgencyOpeningSettlements(context.Context, domain.Cycle, int64) ([]domain.Application, error) {
|
|
return nil, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) MarkAgencyOpeningApplicationGranted(context.Context, string, string, int64) (domain.Application, error) {
|
|
return domain.Application{}, nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) MarkAgencyOpeningApplicationFailed(context.Context, string, string, int64) error {
|
|
return nil
|
|
}
|
|
func (r *agencyOpeningFakeRepo) FinishAgencyOpeningCycleIfComplete(context.Context, string, int64) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
type agencyOpeningFakeAgencySource struct {
|
|
snapshot domain.AgencySnapshot
|
|
ok bool
|
|
}
|
|
|
|
func (s agencyOpeningFakeAgencySource) ResolveOwnerAgency(context.Context, int64) (domain.AgencySnapshot, bool, error) {
|
|
return s.snapshot, s.ok, nil
|
|
}
|
|
|
|
type agencyOpeningFakeRoomClient struct {
|
|
ownerUserID int64
|
|
roomID string
|
|
}
|
|
|
|
func (c *agencyOpeningFakeRoomClient) AdminGetRoom(_ context.Context, req *roomv1.AdminGetRoomRequest, _ ...grpc.CallOption) (*roomv1.AdminGetRoomResponse, error) {
|
|
c.roomID = req.GetRoomId()
|
|
return &roomv1.AdminGetRoomResponse{
|
|
Room: &roomv1.AdminRoomListItem{OwnerUserId: c.ownerUserID},
|
|
}, nil
|
|
}
|
|
|
|
type agencyOpeningFakeWalletClient struct{}
|
|
|
|
func (agencyOpeningFakeWalletClient) CreditAgencyOpeningReward(context.Context, *walletv1.CreditAgencyOpeningRewardRequest, ...grpc.CallOption) (*walletv1.CreditAgencyOpeningRewardResponse, error) {
|
|
return &walletv1.CreditAgencyOpeningRewardResponse{}, nil
|
|
}
|