thread-master/apps/backend/internal/module/member/usecase/invite_test.go

172 lines
6.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package usecase_test
// T219 — M6 invite integration (spec §9.16 IV-01IV-13)
import (
"context"
"testing"
"apps/backend/internal/module/member/domain"
"apps/backend/internal/module/member/usecase"
"github.com/stretchr/testify/require"
)
func TestIV_01_GetMyNetwork(t *testing.T) {
store, svc := newM1Svc()
m, _ := seedMember(t, store, svc, "iv01@test.local")
net, err := svc.GetMyNetwork(context.Background(), m.UID)
require.NoError(t, err)
require.Equal(t, m.UID, net.Me.UID)
require.NotEmpty(t, net.Me.InviteCode)
require.Nil(t, net.Me.ParentUID)
require.Empty(t, net.Downlines)
}
func TestIV_02_ApplyLegalCode(t *testing.T) {
store, svc := newM1Svc()
inv, _ := seedMember(t, store, svc, "iv02-inv@test.local")
me, _ := seedMember(t, store, svc, "iv02-me@test.local")
net, err := svc.ApplyInviteCode(context.Background(), me.UID, inv.InviteCode)
require.NoError(t, err)
require.NotNil(t, net.Me.ParentUID)
require.Equal(t, inv.UID, *net.Me.ParentUID)
require.NotNil(t, net.Upline)
require.Equal(t, inv.UID, net.Upline.UID)
}
func TestIV_03_AlreadyBound(t *testing.T) {
store, svc := newM1Svc()
a, _ := seedMember(t, store, svc, "iv03a@test.local")
b, _ := seedMember(t, store, svc, "iv03b@test.local")
c, _ := seedMember(t, store, svc, "iv03c@test.local")
_, err := svc.ApplyInviteCode(context.Background(), b.UID, a.InviteCode)
require.NoError(t, err)
_, err = svc.ApplyInviteCode(context.Background(), b.UID, c.InviteCode)
require.ErrorIs(t, err, domain.ErrInviteAlreadyBound)
}
func TestIV_04_ApplySelfCode(t *testing.T) {
store, svc := newM1Svc()
me, _ := seedMember(t, store, svc, "iv04@test.local")
_, err := svc.ApplyInviteCode(context.Background(), me.UID, me.InviteCode)
require.ErrorIs(t, err, domain.ErrInviteCodeSelf)
}
func TestIV_05_ApplyUnknownCode(t *testing.T) {
store, svc := newM1Svc()
me, _ := seedMember(t, store, svc, "iv05@test.local")
_, err := svc.ApplyInviteCode(context.Background(), me.UID, "NO-SUCH-CODE")
require.ErrorIs(t, err, domain.ErrInviteCodeNotFound)
}
func TestIV_06_ApplyEmptyCode(t *testing.T) {
store, svc := newM1Svc()
me, _ := seedMember(t, store, svc, "iv06@test.local")
_, err := svc.ApplyInviteCode(context.Background(), me.UID, " ")
require.ErrorIs(t, err, domain.ErrInviteCodeRequired)
}
func TestIV_07_DownlinesCount(t *testing.T) {
store, svc := newM1Svc()
inv, _ := seedMember(t, store, svc, "iv07-inv@test.local")
d1, _ := seedMember(t, store, svc, "iv07-d1@test.local")
d2, _ := seedMember(t, store, svc, "iv07-d2@test.local")
_, err := svc.ApplyInviteCode(context.Background(), d1.UID, inv.InviteCode)
require.NoError(t, err)
_, err = svc.ApplyInviteCode(context.Background(), d2.UID, inv.InviteCode)
require.NoError(t, err)
net, err := svc.GetMyNetwork(context.Background(), inv.UID)
require.NoError(t, err)
require.Len(t, net.Downlines, 2)
require.Equal(t, 2, net.TotalDownlineCount)
require.Equal(t, 2, net.Me.DownlineCount)
}
func TestIV_08_GetTree(t *testing.T) {
store, svc := newM1Svc()
root, _ := seedMember(t, store, svc, "iv08-root@test.local")
child, _ := seedMember(t, store, svc, "iv08-c@test.local")
_, err := svc.ApplyInviteCode(context.Background(), child.UID, root.InviteCode)
require.NoError(t, err)
forest, err := svc.GetInviteTree(context.Background())
require.NoError(t, err)
require.NotEmpty(t, forest)
// find root
var found bool
var walk func([]usecase.InviteTreeNode)
walk = func(nodes []usecase.InviteTreeNode) {
for _, n := range nodes {
if n.UID == root.UID {
found = true
require.NotEmpty(t, n.Children)
}
walk(n.Children)
}
}
walk(forest)
require.True(t, found)
}
func TestIV_09_MoveLegal(t *testing.T) {
store, svc := newM1Svc()
admin, _ := seedAdmin(t, store, svc, "iv09-admin@test.local")
a, _ := seedMember(t, store, svc, "iv09-a@test.local")
b, _ := seedMember(t, store, svc, "iv09-b@test.local")
// b under a
_, err := svc.ApplyInviteCode(context.Background(), b.UID, a.InviteCode)
require.NoError(t, err)
// move b to root
brief, err := svc.MoveInviteMember(context.Background(), admin.UID, b.UID, nil)
require.NoError(t, err)
require.Nil(t, brief.ParentUID)
}
func TestIV_10_NoCycle(t *testing.T) {
store, svc := newM1Svc()
admin, _ := seedAdmin(t, store, svc, "iv10-admin@test.local")
a, _ := seedMember(t, store, svc, "iv10-a@test.local")
b, _ := seedMember(t, store, svc, "iv10-b@test.local")
_, err := svc.ApplyInviteCode(context.Background(), b.UID, a.InviteCode)
require.NoError(t, err)
// move a under b → cycle
_, err = svc.MoveInviteMember(context.Background(), admin.UID, a.UID, &b.UID)
require.ErrorIs(t, err, domain.ErrInviteCycle)
}
func TestIV_11_MoveToSelf(t *testing.T) {
store, svc := newM1Svc()
admin, _ := seedAdmin(t, store, svc, "iv11-admin@test.local")
a, _ := seedMember(t, store, svc, "iv11-a@test.local")
_, err := svc.MoveInviteMember(context.Background(), admin.UID, a.UID, &a.UID)
require.ErrorIs(t, err, domain.ErrInviteSelfParent)
}
func TestIV_12_MemberCannotMove(t *testing.T) {
store, svc := newM1Svc()
mem, _ := seedMember(t, store, svc, "iv12-mem@test.local")
a, _ := seedMember(t, store, svc, "iv12-a@test.local")
b, _ := seedMember(t, store, svc, "iv12-b@test.local")
_, err := svc.MoveInviteMember(context.Background(), mem.UID, a.UID, &b.UID)
require.ErrorIs(t, err, domain.ErrInviteNeedAdmin)
}
func TestIV_13_ListParentCandidatesExcludeSubtree(t *testing.T) {
store, svc := newM1Svc()
a, _ := seedMember(t, store, svc, "iv13-a@test.local")
b, _ := seedMember(t, store, svc, "iv13-b@test.local")
c, _ := seedMember(t, store, svc, "iv13-c@test.local")
_, err := svc.ApplyInviteCode(context.Background(), b.UID, a.InviteCode)
require.NoError(t, err)
_, err = svc.ApplyInviteCode(context.Background(), c.UID, b.InviteCode)
require.NoError(t, err)
// exclude subtree of a → no a,b,c
cands, err := svc.ListParentCandidates(context.Background(), a.UID)
require.NoError(t, err)
for _, x := range cands {
require.NotEqual(t, a.UID, x.UID)
require.NotEqual(t, b.UID, x.UID)
require.NotEqual(t, c.UID, x.UID)
}
}