mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
mockGuildRepoForMail and mockGuildRepoOps each implemented different subsets of the 68-method GuildRepo interface. Adding any new method required updating both mocks. Merged into a single mockGuildRepo with configurable struct fields for error injection and no-op defaults for the rest.
373 lines
8.7 KiB
Go
373 lines
8.7 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"testing"
|
|
|
|
"erupe-ce/common/byteframe"
|
|
cfg "erupe-ce/config"
|
|
"erupe-ce/network/mhfpacket"
|
|
)
|
|
|
|
func TestHandleMsgSysTerminalLog_ReturnsLogIDPlusOne(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysTerminalLog{
|
|
AckHandle: 100,
|
|
LogID: 5,
|
|
Entries: []mhfpacket.TerminalLogEntry{
|
|
{Type1: 1, Type2: 2, Unk0: 3, Unk1: 4, Unk2: 5, Unk3: 6},
|
|
},
|
|
}
|
|
handleMsgSysTerminalLog(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 TestHandleMsgSysLogin_Success(t *testing.T) {
|
|
server := createMockServer()
|
|
server.erupeConfig.DebugOptions.DisableTokenCheck = true
|
|
server.userBinary = NewUserBinaryStore()
|
|
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = charRepo
|
|
|
|
sessionRepo := &mockSessionRepo{}
|
|
server.sessionRepo = sessionRepo
|
|
|
|
userRepo := &mockUserRepoGacha{}
|
|
server.userRepo = userRepo
|
|
|
|
session := createMockSession(0, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLogin{
|
|
AckHandle: 100,
|
|
CharID0: 42,
|
|
LoginTokenString: "test-token",
|
|
}
|
|
handleMsgSysLogin(session, pkt)
|
|
|
|
if session.charID != 42 {
|
|
t.Errorf("Expected charID 42, got %d", session.charID)
|
|
}
|
|
if session.token != "test-token" {
|
|
t.Errorf("Expected token 'test-token', got %q", session.token)
|
|
}
|
|
if sessionRepo.boundToken != "test-token" {
|
|
t.Errorf("Expected BindSession called with 'test-token', got %q", sessionRepo.boundToken)
|
|
}
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// success
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysLogin_GetUserIDError(t *testing.T) {
|
|
server := createMockServer()
|
|
server.erupeConfig.DebugOptions.DisableTokenCheck = true
|
|
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = &mockCharRepoGetUserIDErr{
|
|
mockCharacterRepo: charRepo,
|
|
getUserIDErr: errors.New("user not found"),
|
|
}
|
|
|
|
sessionRepo := &mockSessionRepo{}
|
|
server.sessionRepo = sessionRepo
|
|
|
|
userRepo := &mockUserRepoGacha{}
|
|
server.userRepo = userRepo
|
|
|
|
session := createMockSession(0, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLogin{
|
|
AckHandle: 100,
|
|
CharID0: 42,
|
|
LoginTokenString: "test-token",
|
|
}
|
|
handleMsgSysLogin(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// got a response (fail ACK)
|
|
default:
|
|
t.Error("No response packet queued on GetUserID error")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysLogin_BindSessionError(t *testing.T) {
|
|
server := createMockServer()
|
|
server.erupeConfig.DebugOptions.DisableTokenCheck = true
|
|
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = charRepo
|
|
|
|
sessionRepo := &mockSessionRepo{bindErr: errors.New("bind failed")}
|
|
server.sessionRepo = sessionRepo
|
|
|
|
userRepo := &mockUserRepoGacha{}
|
|
server.userRepo = userRepo
|
|
|
|
session := createMockSession(0, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLogin{
|
|
AckHandle: 100,
|
|
CharID0: 42,
|
|
LoginTokenString: "test-token",
|
|
}
|
|
handleMsgSysLogin(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// got a response (fail ACK)
|
|
default:
|
|
t.Error("No response packet queued on BindSession error")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysLogin_SetLastCharacterError(t *testing.T) {
|
|
server := createMockServer()
|
|
server.erupeConfig.DebugOptions.DisableTokenCheck = true
|
|
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = charRepo
|
|
|
|
sessionRepo := &mockSessionRepo{}
|
|
server.sessionRepo = sessionRepo
|
|
|
|
userRepo := &mockUserRepoGacha{setLastCharErr: errors.New("set failed")}
|
|
server.userRepo = userRepo
|
|
|
|
session := createMockSession(0, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLogin{
|
|
AckHandle: 100,
|
|
CharID0: 42,
|
|
LoginTokenString: "test-token",
|
|
}
|
|
handleMsgSysLogin(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// got a response (fail ACK)
|
|
default:
|
|
t.Error("No response packet queued on SetLastCharacter error")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysPing_Session(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysPing{AckHandle: 100}
|
|
handleMsgSysPing(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Fatal("Empty response")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysIssueLogkey_GeneratesKey(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysIssueLogkey{AckHandle: 100}
|
|
handleMsgSysIssueLogkey(session, pkt)
|
|
|
|
if len(session.logKey) != 16 {
|
|
t.Errorf("Expected 16-byte log key, got %d bytes", len(session.logKey))
|
|
}
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Fatal("Empty response")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysRecordLog_ZZMode(t *testing.T) {
|
|
server := createMockServer()
|
|
server.erupeConfig.RealClientMode = cfg.ZZ
|
|
server.userBinary = NewUserBinaryStore()
|
|
|
|
guildRepo := &mockGuildRepo{}
|
|
server.guildRepo = guildRepo
|
|
|
|
session := createMockSession(1, server)
|
|
|
|
// Create a stage for the session (handler accesses s.stage.reservedClientSlots)
|
|
stage := &Stage{
|
|
id: "testStage",
|
|
clients: make(map[*Session]uint32),
|
|
reservedClientSlots: make(map[uint32]bool),
|
|
}
|
|
stage.reservedClientSlots[1] = true
|
|
session.stage = stage
|
|
|
|
// Build kill log data: 32 header bytes + 176 monster bytes
|
|
data := make([]byte, 32+176)
|
|
// Set monster index 5 to have 2 kills (a large monster per mhfmon)
|
|
data[32+5] = 2
|
|
|
|
pkt := &mhfpacket.MsgSysRecordLog{
|
|
AckHandle: 100,
|
|
Data: data,
|
|
}
|
|
handleMsgSysRecordLog(session, pkt)
|
|
|
|
// Check that reserved slot was cleaned up
|
|
if _, exists := stage.reservedClientSlots[1]; exists {
|
|
t.Error("Expected reserved client slot to be removed")
|
|
}
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// success
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysLockGlobalSema_LocalChannel(t *testing.T) {
|
|
server := createMockServer()
|
|
server.GlobalID = "ch1"
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLockGlobalSema{
|
|
AckHandle: 100,
|
|
UserIDString: "someStage",
|
|
ServerChannelIDString: "ch1",
|
|
}
|
|
handleMsgSysLockGlobalSema(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Fatal("Empty response")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysLockGlobalSema_RemoteMatch(t *testing.T) {
|
|
server := createMockServer()
|
|
server.GlobalID = "ch1"
|
|
|
|
otherChannel := createMockServer()
|
|
otherChannel.GlobalID = "ch2"
|
|
otherChannel.stages.Store("prefix_testStage", &Stage{
|
|
id: "prefix_testStage",
|
|
clients: make(map[*Session]uint32),
|
|
reservedClientSlots: make(map[uint32]bool),
|
|
})
|
|
server.Registry = NewLocalChannelRegistry([]*Server{server, otherChannel})
|
|
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysLockGlobalSema{
|
|
AckHandle: 100,
|
|
UserIDString: "testStage",
|
|
ServerChannelIDString: "ch1",
|
|
}
|
|
handleMsgSysLockGlobalSema(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Fatal("Empty response")
|
|
}
|
|
_ = byteframe.NewByteFrameFromBytes(p.data)
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysUnlockGlobalSema_Session(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgSysUnlockGlobalSema{AckHandle: 100}
|
|
handleMsgSysUnlockGlobalSema(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// success
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgSysRightsReload_Session(t *testing.T) {
|
|
server := createMockServer()
|
|
userRepo := &mockUserRepoGacha{rights: 0x02}
|
|
server.userRepo = userRepo
|
|
|
|
session := createMockSession(1, server)
|
|
session.userID = 1
|
|
|
|
pkt := &mhfpacket.MsgSysRightsReload{AckHandle: 100}
|
|
handleMsgSysRightsReload(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// success
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfAnnounce_Session(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
dataBf := byteframe.NewByteFrame()
|
|
dataBf.WriteUint8(2) // type = berserk
|
|
|
|
pkt := &mhfpacket.MsgMhfAnnounce{
|
|
AckHandle: 100,
|
|
IPAddress: binary.LittleEndian.Uint32([]byte{127, 0, 0, 1}),
|
|
Port: 54001,
|
|
StageID: make([]byte, 32),
|
|
Data: byteframe.NewByteFrameFromBytes(dataBf.Data()),
|
|
}
|
|
handleMsgMhfAnnounce(session, pkt)
|
|
|
|
select {
|
|
case <-session.sendPackets:
|
|
// success
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// mockCharRepoGetUserIDErr wraps mockCharacterRepo to return an error from GetUserID
|
|
type mockCharRepoGetUserIDErr struct {
|
|
*mockCharacterRepo
|
|
getUserIDErr error
|
|
}
|
|
|
|
func (m *mockCharRepoGetUserIDErr) GetUserID(_ uint32) (uint32, error) {
|
|
return 0, m.getUserIDErr
|
|
}
|