Files
Erupe/server/channelserver/handlers_semaphore_test.go
Houmgaor be4cd2001c test: import 38 channelserver test files from v9.2.x-stable
Port test files from v9.2.x-stable branch to increase channelserver
coverage from 13.8% to 25.6% (556 tests passing).

Adapted all files to main's struct definitions: config import alias,
Airou/CatDefinition rename, packet field mismatches, Raviente struct
differences, and maxPlayers defaults. Removed tests referencing
production code not yet on main (Player, FestivalColour, etc.).
Excluded handlers_register_test.go (Raviente completely redesigned).
2026-02-16 22:19:44 +01:00

448 lines
11 KiB
Go

package channelserver
import (
"testing"
"erupe-ce/network/mhfpacket"
)
func TestHandleMsgSysCreateSemaphore(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgSysCreateSemaphore{
AckHandle: 12345,
Unk0: 0,
}
handleMsgSysCreateSemaphore(session, pkt)
// Verify response packet was queued
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgSysDeleteSemaphore_NoSemaphores(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgSysDeleteSemaphore{
SemaphoreID: 12345,
}
// Should not panic when no semaphores exist
defer func() {
if r := recover(); r != nil {
t.Errorf("handleMsgSysDeleteSemaphore panicked: %v", r)
}
}()
handleMsgSysDeleteSemaphore(session, pkt)
}
func TestHandleMsgSysDeleteSemaphore_WithSemaphore(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create a semaphore
sema := NewSemaphore(session, "test_sema", 4)
server.semaphore["test_sema"] = sema
pkt := &mhfpacket.MsgSysDeleteSemaphore{
SemaphoreID: sema.id,
}
handleMsgSysDeleteSemaphore(session, pkt)
// Semaphore should be deleted
if _, exists := server.semaphore["test_sema"]; exists {
t.Error("Semaphore should be deleted")
}
}
func TestHandleMsgSysCreateAcquireSemaphore_NewSemaphore(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
pkt := &mhfpacket.MsgSysCreateAcquireSemaphore{
AckHandle: 12345,
Unk0: 0,
PlayerCount: 4,
SemaphoreID: "test_semaphore",
}
handleMsgSysCreateAcquireSemaphore(session, pkt)
// Verify response packet was queued
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
// Verify semaphore was created
if _, exists := server.semaphore["test_semaphore"]; !exists {
t.Error("Semaphore should be created")
}
}
func TestHandleMsgSysCreateAcquireSemaphore_ExistingSemaphore(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Pre-create semaphore
sema := NewSemaphore(session, "existing_sema", 4)
server.semaphore["existing_sema"] = sema
pkt := &mhfpacket.MsgSysCreateAcquireSemaphore{
AckHandle: 12345,
Unk0: 0,
PlayerCount: 4,
SemaphoreID: "existing_sema",
}
handleMsgSysCreateAcquireSemaphore(session, pkt)
// Verify response packet was queued
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
// Verify client was added to semaphore
if len(sema.clients) == 0 {
t.Error("Session should be added to semaphore")
}
}
func TestHandleMsgSysCreateAcquireSemaphore_RavienteSemaphore(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Test raviente semaphore (special prefix)
pkt := &mhfpacket.MsgSysCreateAcquireSemaphore{
AckHandle: 12345,
Unk0: 0,
PlayerCount: 32,
SemaphoreID: "hs_l0u3B51", // Raviente prefix + suffix
}
handleMsgSysCreateAcquireSemaphore(session, pkt)
// Verify response packet was queued
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
// Verify raviente semaphore was created with special settings
if sema, exists := server.semaphore["hs_l0u3B51"]; !exists {
t.Error("Raviente semaphore should be created")
} else if sema.maxPlayers != 127 {
t.Errorf("Raviente semaphore maxPlayers = %d, want 127", sema.maxPlayers)
}
}
func TestHandleMsgSysCreateAcquireSemaphore_Full(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
// Create semaphore with 1 player max
session1 := createMockSession(1, server)
sema := NewSemaphore(session1, "full_sema", 1)
server.semaphore["full_sema"] = sema
// Fill the semaphore
sema.clients[session1] = session1.charID
// Try to acquire with another session
session2 := createMockSession(2, server)
pkt := &mhfpacket.MsgSysCreateAcquireSemaphore{
AckHandle: 12345,
Unk0: 0,
PlayerCount: 1,
SemaphoreID: "full_sema",
}
handleMsgSysCreateAcquireSemaphore(session2, pkt)
// Should still respond (with failure indication)
select {
case p := <-session2.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data even for full semaphore")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgSysAcquireSemaphore_Exists(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create semaphore
sema := NewSemaphore(session, "acquire_test", 4)
server.semaphore["acquire_test"] = sema
pkt := &mhfpacket.MsgSysAcquireSemaphore{
AckHandle: 12345,
SemaphoreID: "acquire_test",
}
handleMsgSysAcquireSemaphore(session, pkt)
// Verify response packet was queued
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
// Verify host was set
if sema.host != session {
t.Error("Session should be set as semaphore host")
}
}
func TestHandleMsgSysAcquireSemaphore_NotExists(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
pkt := &mhfpacket.MsgSysAcquireSemaphore{
AckHandle: 12345,
SemaphoreID: "nonexistent",
}
handleMsgSysAcquireSemaphore(session, pkt)
// Should respond with failure
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Error("Response packet should have data")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgSysReleaseSemaphore(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
// Should not panic (mostly empty handler)
defer func() {
if r := recover(); r != nil {
t.Errorf("handleMsgSysReleaseSemaphore panicked: %v", r)
}
}()
pkt := &mhfpacket.MsgSysReleaseSemaphore{}
handleMsgSysReleaseSemaphore(session, pkt)
}
func TestHandleMsgSysCheckSemaphore_Exists(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create semaphore
sema := NewSemaphore(session, "check_test", 4)
server.semaphore["check_test"] = sema
pkt := &mhfpacket.MsgSysCheckSemaphore{
AckHandle: 12345,
SemaphoreID: "check_test",
}
handleMsgSysCheckSemaphore(session, pkt)
// Verify response indicates semaphore exists
select {
case p := <-session.sendPackets:
if len(p.data) < 4 {
t.Error("Response packet should have at least 4 bytes")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgSysCheckSemaphore_NotExists(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
pkt := &mhfpacket.MsgSysCheckSemaphore{
AckHandle: 12345,
SemaphoreID: "nonexistent",
}
handleMsgSysCheckSemaphore(session, pkt)
// Verify response indicates semaphore does not exist
select {
case p := <-session.sendPackets:
if len(p.data) < 4 {
t.Error("Response packet should have at least 4 bytes")
}
default:
t.Error("No response packet queued")
}
}
func TestRemoveSessionFromSemaphore(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create semaphore and add session
sema := NewSemaphore(session, "remove_test", 4)
sema.clients[session] = session.charID
server.semaphore["remove_test"] = sema
// Remove session
removeSessionFromSemaphore(session)
// Verify session was removed
if _, exists := sema.clients[session]; exists {
t.Error("Session should be removed from clients")
}
}
func TestRemoveSessionFromSemaphore_MultipleSemaphores(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create multiple semaphores with the session
for i := 0; i < 3; i++ {
sema := NewSemaphore(session, "multi_test_"+string(rune('a'+i)), 4)
sema.clients[session] = session.charID
server.semaphore["multi_test_"+string(rune('a'+i))] = sema
}
// Remove session from all
removeSessionFromSemaphore(session)
// Verify session was removed from all semaphores
for _, sema := range server.semaphore {
if _, exists := sema.clients[session]; exists {
t.Error("Session should be removed from all semaphore clients")
}
}
}
func TestDestructEmptySemaphores(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
session := createMockSession(1, server)
// Create empty semaphore
sema := NewSemaphore(session, "empty_sema", 4)
server.semaphore["empty_sema"] = sema
// Create non-empty semaphore
semaWithClients := NewSemaphore(session, "with_clients", 4)
semaWithClients.clients[session] = session.charID
server.semaphore["with_clients"] = semaWithClients
destructEmptySemaphores(session)
// Empty semaphore should be deleted
if _, exists := server.semaphore["empty_sema"]; exists {
t.Error("Empty semaphore should be deleted")
}
// Non-empty semaphore should remain
if _, exists := server.semaphore["with_clients"]; !exists {
t.Error("Non-empty semaphore should remain")
}
}
func TestSemaphoreHandlers_SequentialAcquire(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
// Sequentially try to create/acquire the same semaphore
// Note: the handler has race conditions when accessed concurrently
for i := 0; i < 5; i++ {
session := createMockSession(uint32(i), server)
pkt := &mhfpacket.MsgSysCreateAcquireSemaphore{
AckHandle: uint32(i),
Unk0: 0,
PlayerCount: 4,
SemaphoreID: "sequential_test",
}
handleMsgSysCreateAcquireSemaphore(session, pkt)
// Drain send queue
select {
case <-session.sendPackets:
default:
}
}
// Semaphore should exist
if _, exists := server.semaphore["sequential_test"]; !exists {
t.Error("Semaphore should exist after sequential acquires")
}
}
func TestSemaphoreHandlers_MultipleCheck(t *testing.T) {
server := createMockServer()
server.semaphore = make(map[string]*Semaphore)
// Create semaphore
helperSession := createMockSession(99, server)
sema := NewSemaphore(helperSession, "check_multiple", 4)
server.semaphore["check_multiple"] = sema
// Check the semaphore from multiple sessions sequentially
for i := 0; i < 5; i++ {
session := createMockSession(uint32(i), server)
pkt := &mhfpacket.MsgSysCheckSemaphore{
AckHandle: uint32(i),
SemaphoreID: "check_multiple",
}
handleMsgSysCheckSemaphore(session, pkt)
// Drain send queue
select {
case <-session.sendPackets:
default:
}
}
}