mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 23:54:33 +01:00
Scout invitations were stored in guild_applications with type 'invited', forcing the scout list response to use charID as the invitation ID — a known hack that made CancelGuildScout semantically incorrect. Introduce a dedicated guild_invites table (migration 0012) with a serial PK. The scout list now returns real invite IDs and actual InvitedAt timestamps. CancelGuildScout cancels by PK. AcceptInvite and DeclineInvite operate on guild_invites while player-applied applications remain in guild_applications unchanged.
497 lines
11 KiB
Go
497 lines
11 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"erupe-ce/network/mhfpacket"
|
|
)
|
|
|
|
// --- handleMsgMhfAnswerGuildScout tests ---
|
|
|
|
func TestAnswerGuildScout_Accept(t *testing.T) {
|
|
server := createMockServer()
|
|
mailMock := &mockMailRepo{}
|
|
guildMock := &mockGuildRepo{
|
|
hasInviteResult: true,
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 50
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = mailMock
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
|
|
AckHandle: 100,
|
|
LeaderID: 50,
|
|
Answer: true,
|
|
}
|
|
|
|
handleMsgMhfAnswerGuildScout(session, pkt)
|
|
|
|
if guildMock.acceptInviteCharID != 1 {
|
|
t.Errorf("AcceptInvite charID = %d, want 1", guildMock.acceptInviteCharID)
|
|
}
|
|
if len(mailMock.sentMails) != 2 {
|
|
t.Fatalf("Expected 2 mails (self + leader), got %d", len(mailMock.sentMails))
|
|
}
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestAnswerGuildScout_Decline(t *testing.T) {
|
|
server := createMockServer()
|
|
mailMock := &mockMailRepo{}
|
|
guildMock := &mockGuildRepo{
|
|
hasInviteResult: true,
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 50
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = mailMock
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
|
|
AckHandle: 100,
|
|
LeaderID: 50,
|
|
Answer: false,
|
|
}
|
|
|
|
handleMsgMhfAnswerGuildScout(session, pkt)
|
|
|
|
if guildMock.declineInviteCharID != 1 {
|
|
t.Errorf("DeclineInvite charID = %d, want 1", guildMock.declineInviteCharID)
|
|
}
|
|
if len(mailMock.sentMails) != 2 {
|
|
t.Fatalf("Expected 2 mails (self + leader), got %d", len(mailMock.sentMails))
|
|
}
|
|
}
|
|
|
|
func TestAnswerGuildScout_GuildNotFound(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{}
|
|
guildMock.getErr = errNotFound
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = &mockMailRepo{}
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
|
|
AckHandle: 100,
|
|
LeaderID: 50,
|
|
Answer: true,
|
|
}
|
|
|
|
handleMsgMhfAnswerGuildScout(session, pkt)
|
|
|
|
// Should return fail ack
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestAnswerGuildScout_ApplicationMissing(t *testing.T) {
|
|
server := createMockServer()
|
|
mailMock := &mockMailRepo{}
|
|
guildMock := &mockGuildRepo{
|
|
hasInviteResult: false, // no invite found
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 50
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = mailMock
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
|
|
AckHandle: 100,
|
|
LeaderID: 50,
|
|
Answer: true,
|
|
}
|
|
|
|
handleMsgMhfAnswerGuildScout(session, pkt)
|
|
|
|
// No mails should be sent when application is missing
|
|
if len(mailMock.sentMails) != 0 {
|
|
t.Errorf("Expected 0 mails for missing application, got %d", len(mailMock.sentMails))
|
|
}
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestAnswerGuildScout_MailError(t *testing.T) {
|
|
server := createMockServer()
|
|
mailMock := &mockMailRepo{sendErr: errNotFound}
|
|
guildMock := &mockGuildRepo{
|
|
hasInviteResult: true,
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 50
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = mailMock
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
|
|
AckHandle: 100,
|
|
LeaderID: 50,
|
|
Answer: true,
|
|
}
|
|
|
|
// Should not panic; mail errors logged as warnings
|
|
handleMsgMhfAnswerGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- handleMsgMhfGetRejectGuildScout tests ---
|
|
|
|
func TestGetRejectGuildScout_Restricted(t *testing.T) {
|
|
server := createMockServer()
|
|
charMock := newMockCharacterRepo()
|
|
charMock.bools["restrict_guild_scout"] = true
|
|
server.charRepo = charMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
|
|
|
|
handleMsgMhfGetRejectGuildScout(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) < 4 {
|
|
t.Fatal("Response too short")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestGetRejectGuildScout_Open(t *testing.T) {
|
|
server := createMockServer()
|
|
charMock := newMockCharacterRepo()
|
|
charMock.bools["restrict_guild_scout"] = false
|
|
server.charRepo = charMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
|
|
|
|
handleMsgMhfGetRejectGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestGetRejectGuildScout_DBError(t *testing.T) {
|
|
server := createMockServer()
|
|
charMock := newMockCharacterRepo()
|
|
charMock.readErr = errNotFound
|
|
server.charRepo = charMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
|
|
|
|
handleMsgMhfGetRejectGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- handleMsgMhfSetRejectGuildScout tests ---
|
|
|
|
func TestSetRejectGuildScout_Success(t *testing.T) {
|
|
server := createMockServer()
|
|
charMock := newMockCharacterRepo()
|
|
server.charRepo = charMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfSetRejectGuildScout{
|
|
AckHandle: 100,
|
|
Reject: true,
|
|
}
|
|
|
|
handleMsgMhfSetRejectGuildScout(session, pkt)
|
|
|
|
if !charMock.bools["restrict_guild_scout"] {
|
|
t.Error("restrict_guild_scout should be true")
|
|
}
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestSetRejectGuildScout_DBError(t *testing.T) {
|
|
server := createMockServer()
|
|
charMock := newMockCharacterRepo()
|
|
charMock.saveErr = errNotFound
|
|
server.charRepo = charMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfSetRejectGuildScout{
|
|
AckHandle: 100,
|
|
Reject: true,
|
|
}
|
|
|
|
handleMsgMhfSetRejectGuildScout(session, pkt)
|
|
|
|
// Should return fail ack
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- handleMsgMhfPostGuildScout tests ---
|
|
|
|
func TestPostGuildScout_Success(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
membership: &GuildMember{GuildID: 10, Recruiter: true},
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 1
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = &mockMailRepo{}
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfPostGuildScout{
|
|
AckHandle: 100,
|
|
CharID: 42,
|
|
}
|
|
|
|
handleMsgMhfPostGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestPostGuildScout_AlreadyInvited(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
membership: &GuildMember{GuildID: 10, Recruiter: true},
|
|
createAppErr: ErrAlreadyInvited,
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock.guild.LeaderCharID = 1
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = &mockMailRepo{}
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfPostGuildScout{
|
|
AckHandle: 100,
|
|
CharID: 42,
|
|
}
|
|
|
|
handleMsgMhfPostGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestPostGuildScout_Error(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
getMemberErr: errNotFound,
|
|
}
|
|
server.guildRepo = guildMock
|
|
server.mailRepo = &mockMailRepo{}
|
|
ensureGuildService(server)
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfPostGuildScout{
|
|
AckHandle: 100,
|
|
CharID: 42,
|
|
}
|
|
|
|
handleMsgMhfPostGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- handleMsgMhfCancelGuildScout tests ---
|
|
|
|
func TestCancelGuildScout_Success(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
membership: &GuildMember{GuildID: 10, Recruiter: true},
|
|
}
|
|
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCancelGuildScout{
|
|
AckHandle: 100,
|
|
InvitationID: 42,
|
|
}
|
|
|
|
handleMsgMhfCancelGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestCancelGuildScout_NoMembership(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
getMemberErr: errNotFound,
|
|
}
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCancelGuildScout{
|
|
AckHandle: 100,
|
|
InvitationID: 42,
|
|
}
|
|
|
|
handleMsgMhfCancelGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestCancelGuildScout_NilMembership(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
membership: nil,
|
|
}
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCancelGuildScout{
|
|
AckHandle: 100,
|
|
InvitationID: 42,
|
|
}
|
|
|
|
handleMsgMhfCancelGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestCancelGuildScout_GuildNotFound(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{
|
|
membership: &GuildMember{GuildID: 99, Recruiter: true},
|
|
getErr: errNotFound,
|
|
}
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCancelGuildScout{
|
|
AckHandle: 100,
|
|
InvitationID: 42,
|
|
}
|
|
|
|
handleMsgMhfCancelGuildScout(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- handleMsgMhfGetGuildScoutList tests ---
|
|
|
|
func TestGetGuildScoutList_NoGuildNoPrevID(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{} // GetByCharID returns nil
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
session.prevGuildID = 0
|
|
|
|
pkt := &mhfpacket.MsgMhfGetGuildScoutList{AckHandle: 100}
|
|
|
|
handleMsgMhfGetGuildScoutList(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestGetGuildScoutList_NilGuildWithPrevID_GetByIDFails(t *testing.T) {
|
|
server := createMockServer()
|
|
guildMock := &mockGuildRepo{} // GetByCharID returns nil, GetByID for prevGuildID returns not found
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
session.prevGuildID = 99 // non-zero triggers else branch
|
|
|
|
pkt := &mhfpacket.MsgMhfGetGuildScoutList{AckHandle: 100}
|
|
|
|
handleMsgMhfGetGuildScoutList(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestGetGuildScoutList_WithGuild(t *testing.T) {
|
|
server := createMockServer()
|
|
guild := &Guild{ID: 10, Name: "TestGuild"}
|
|
guildMock := &mockGuildRepo{}
|
|
guildMock.guild = guild
|
|
server.guildRepo = guildMock
|
|
session := createMockSession(1, server)
|
|
session.prevGuildID = 10
|
|
|
|
pkt := &mhfpacket.MsgMhfGetGuildScoutList{AckHandle: 100}
|
|
|
|
handleMsgMhfGetGuildScoutList(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|