mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 17:43:21 +01:00
fix(crashes): trying to investigate the causes of crash.
New unit tests to that end.
This commit is contained in:
481
server/channelserver/handlers_house_test.go
Normal file
481
server/channelserver/handlers_house_test.go
Normal file
@@ -0,0 +1,481 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"erupe-ce/common/mhfitem"
|
||||
"erupe-ce/common/token"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// createTestEquipment creates properly initialized test equipment
|
||||
func createTestEquipment(itemIDs []uint16, warehouseIDs []uint32) []mhfitem.MHFEquipment {
|
||||
var equip []mhfitem.MHFEquipment
|
||||
for i, itemID := range itemIDs {
|
||||
e := mhfitem.MHFEquipment{
|
||||
ItemID: itemID,
|
||||
WarehouseID: warehouseIDs[i],
|
||||
Decorations: make([]mhfitem.MHFItem, 3),
|
||||
Sigils: make([]mhfitem.MHFSigil, 3),
|
||||
}
|
||||
// Initialize Sigils Effects arrays
|
||||
for j := 0; j < 3; j++ {
|
||||
e.Sigils[j].Effects = make([]mhfitem.MHFSigilEffect, 3)
|
||||
}
|
||||
equip = append(equip, e)
|
||||
}
|
||||
return equip
|
||||
}
|
||||
|
||||
// TestWarehouseItemSerialization verifies warehouse item serialization
|
||||
func TestWarehouseItemSerialization(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
items []mhfitem.MHFItemStack
|
||||
}{
|
||||
{
|
||||
name: "empty_warehouse",
|
||||
items: []mhfitem.MHFItemStack{},
|
||||
},
|
||||
{
|
||||
name: "single_item",
|
||||
items: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple_items",
|
||||
items: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
{Item: mhfitem.MHFItem{ItemID: 2}, Quantity: 20},
|
||||
{Item: mhfitem.MHFItem{ItemID: 3}, Quantity: 30},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Serialize
|
||||
serialized := mhfitem.SerializeWarehouseItems(tt.items)
|
||||
|
||||
// Basic validation
|
||||
if serialized == nil {
|
||||
t.Error("serialization returned nil")
|
||||
}
|
||||
|
||||
// Verify we can work with the serialized data
|
||||
if len(serialized) < 0 {
|
||||
t.Error("invalid serialized length")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseEquipmentSerialization verifies warehouse equipment serialization
|
||||
func TestWarehouseEquipmentSerialization(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
equipment []mhfitem.MHFEquipment
|
||||
}{
|
||||
{
|
||||
name: "empty_equipment",
|
||||
equipment: []mhfitem.MHFEquipment{},
|
||||
},
|
||||
{
|
||||
name: "single_equipment",
|
||||
equipment: createTestEquipment([]uint16{100}, []uint32{1}),
|
||||
},
|
||||
{
|
||||
name: "multiple_equipment",
|
||||
equipment: createTestEquipment([]uint16{100, 101, 102}, []uint32{1, 2, 3}),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Serialize
|
||||
serialized := mhfitem.SerializeWarehouseEquipment(tt.equipment)
|
||||
|
||||
// Basic validation
|
||||
if serialized == nil {
|
||||
t.Error("serialization returned nil")
|
||||
}
|
||||
|
||||
// Verify we can work with the serialized data
|
||||
if len(serialized) < 0 {
|
||||
t.Error("invalid serialized length")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseItemDiff verifies the item diff calculation
|
||||
func TestWarehouseItemDiff(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
oldItems []mhfitem.MHFItemStack
|
||||
newItems []mhfitem.MHFItemStack
|
||||
wantDiff bool
|
||||
}{
|
||||
{
|
||||
name: "no_changes",
|
||||
oldItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10}},
|
||||
newItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10}},
|
||||
wantDiff: false,
|
||||
},
|
||||
{
|
||||
name: "quantity_changed",
|
||||
oldItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10}},
|
||||
newItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 15}},
|
||||
wantDiff: true,
|
||||
},
|
||||
{
|
||||
name: "item_added",
|
||||
oldItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10}},
|
||||
newItems: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
{Item: mhfitem.MHFItem{ItemID: 2}, Quantity: 5},
|
||||
},
|
||||
wantDiff: true,
|
||||
},
|
||||
{
|
||||
name: "item_removed",
|
||||
oldItems: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
{Item: mhfitem.MHFItem{ItemID: 2}, Quantity: 5},
|
||||
},
|
||||
newItems: []mhfitem.MHFItemStack{{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10}},
|
||||
wantDiff: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
diff := mhfitem.DiffItemStacks(tt.oldItems, tt.newItems)
|
||||
|
||||
// Verify that diff returns a valid result (not nil)
|
||||
if diff == nil {
|
||||
t.Error("diff should not be nil")
|
||||
}
|
||||
|
||||
// The diff function returns items where Quantity > 0
|
||||
// So with no changes (all same quantity), diff should have same items
|
||||
if tt.name == "no_changes" {
|
||||
if len(diff) == 0 {
|
||||
t.Error("no_changes should return items")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseEquipmentMerge verifies equipment merging logic
|
||||
func TestWarehouseEquipmentMerge(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
oldEquip []mhfitem.MHFEquipment
|
||||
newEquip []mhfitem.MHFEquipment
|
||||
wantMerged int
|
||||
}{
|
||||
{
|
||||
name: "merge_empty",
|
||||
oldEquip: []mhfitem.MHFEquipment{},
|
||||
newEquip: []mhfitem.MHFEquipment{},
|
||||
wantMerged: 0,
|
||||
},
|
||||
{
|
||||
name: "add_new_equipment",
|
||||
oldEquip: []mhfitem.MHFEquipment{
|
||||
{ItemID: 100, WarehouseID: 1},
|
||||
},
|
||||
newEquip: []mhfitem.MHFEquipment{
|
||||
{ItemID: 101, WarehouseID: 0}, // New item, no warehouse ID yet
|
||||
},
|
||||
wantMerged: 2, // Old + new
|
||||
},
|
||||
{
|
||||
name: "update_existing_equipment",
|
||||
oldEquip: []mhfitem.MHFEquipment{
|
||||
{ItemID: 100, WarehouseID: 1},
|
||||
},
|
||||
newEquip: []mhfitem.MHFEquipment{
|
||||
{ItemID: 101, WarehouseID: 1}, // Update existing
|
||||
},
|
||||
wantMerged: 1, // Updated in place
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Simulate the merge logic from handleMsgMhfUpdateWarehouse
|
||||
var finalEquip []mhfitem.MHFEquipment
|
||||
oEquips := tt.oldEquip
|
||||
|
||||
for _, uEquip := range tt.newEquip {
|
||||
exists := false
|
||||
for i := range oEquips {
|
||||
if oEquips[i].WarehouseID == uEquip.WarehouseID && uEquip.WarehouseID != 0 {
|
||||
exists = true
|
||||
oEquips[i].ItemID = uEquip.ItemID
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
// Generate new warehouse ID
|
||||
uEquip.WarehouseID = token.RNG.Uint32()
|
||||
finalEquip = append(finalEquip, uEquip)
|
||||
}
|
||||
}
|
||||
|
||||
for _, oEquip := range oEquips {
|
||||
if oEquip.ItemID > 0 {
|
||||
finalEquip = append(finalEquip, oEquip)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify merge result count
|
||||
if len(finalEquip) < 0 {
|
||||
t.Error("invalid merged equipment count")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseIDGeneration verifies warehouse ID uniqueness
|
||||
func TestWarehouseIDGeneration(t *testing.T) {
|
||||
// Generate multiple warehouse IDs and verify they're unique
|
||||
idCount := 100
|
||||
ids := make(map[uint32]bool)
|
||||
|
||||
for i := 0; i < idCount; i++ {
|
||||
id := token.RNG.Uint32()
|
||||
if id == 0 {
|
||||
t.Error("generated warehouse ID is 0 (invalid)")
|
||||
}
|
||||
if ids[id] {
|
||||
// While collisions are possible with random IDs,
|
||||
// they should be extremely rare
|
||||
t.Logf("Warning: duplicate warehouse ID generated: %d", id)
|
||||
}
|
||||
ids[id] = true
|
||||
}
|
||||
|
||||
if len(ids) < idCount*90/100 {
|
||||
t.Errorf("too many duplicate IDs: got %d unique out of %d", len(ids), idCount)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseItemRemoval verifies item removal logic
|
||||
func TestWarehouseItemRemoval(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
items []mhfitem.MHFItemStack
|
||||
removeID uint16
|
||||
wantRemain int
|
||||
}{
|
||||
{
|
||||
name: "remove_existing",
|
||||
items: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
{Item: mhfitem.MHFItem{ItemID: 2}, Quantity: 20},
|
||||
},
|
||||
removeID: 1,
|
||||
wantRemain: 1,
|
||||
},
|
||||
{
|
||||
name: "remove_non_existing",
|
||||
items: []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
},
|
||||
removeID: 999,
|
||||
wantRemain: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var remaining []mhfitem.MHFItemStack
|
||||
for _, item := range tt.items {
|
||||
if item.Item.ItemID != tt.removeID {
|
||||
remaining = append(remaining, item)
|
||||
}
|
||||
}
|
||||
|
||||
if len(remaining) != tt.wantRemain {
|
||||
t.Errorf("expected %d remaining items, got %d", tt.wantRemain, len(remaining))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseEquipmentRemoval verifies equipment removal logic
|
||||
func TestWarehouseEquipmentRemoval(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
equipment []mhfitem.MHFEquipment
|
||||
setZeroID uint32
|
||||
wantActive int
|
||||
}{
|
||||
{
|
||||
name: "remove_by_setting_zero",
|
||||
equipment: []mhfitem.MHFEquipment{
|
||||
{ItemID: 100, WarehouseID: 1},
|
||||
{ItemID: 101, WarehouseID: 2},
|
||||
},
|
||||
setZeroID: 1,
|
||||
wantActive: 1,
|
||||
},
|
||||
{
|
||||
name: "all_active",
|
||||
equipment: []mhfitem.MHFEquipment{
|
||||
{ItemID: 100, WarehouseID: 1},
|
||||
{ItemID: 101, WarehouseID: 2},
|
||||
},
|
||||
setZeroID: 999,
|
||||
wantActive: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Simulate removal by setting ItemID to 0
|
||||
equipment := make([]mhfitem.MHFEquipment, len(tt.equipment))
|
||||
copy(equipment, tt.equipment)
|
||||
|
||||
for i := range equipment {
|
||||
if equipment[i].WarehouseID == tt.setZeroID {
|
||||
equipment[i].ItemID = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Count active equipment (ItemID > 0)
|
||||
activeCount := 0
|
||||
for _, eq := range equipment {
|
||||
if eq.ItemID > 0 {
|
||||
activeCount++
|
||||
}
|
||||
}
|
||||
|
||||
if activeCount != tt.wantActive {
|
||||
t.Errorf("expected %d active equipment, got %d", tt.wantActive, activeCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseBoxIndexValidation verifies box index bounds
|
||||
func TestWarehouseBoxIndexValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
boxIndex uint8
|
||||
isValid bool
|
||||
}{
|
||||
{
|
||||
name: "box_0",
|
||||
boxIndex: 0,
|
||||
isValid: true,
|
||||
},
|
||||
{
|
||||
name: "box_1",
|
||||
boxIndex: 1,
|
||||
isValid: true,
|
||||
},
|
||||
{
|
||||
name: "box_9",
|
||||
boxIndex: 9,
|
||||
isValid: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Verify box index is within reasonable bounds
|
||||
if tt.isValid && tt.boxIndex > 100 {
|
||||
t.Error("box index unreasonably high")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWarehouseErrorRecovery verifies error handling doesn't corrupt state
|
||||
func TestWarehouseErrorRecovery(t *testing.T) {
|
||||
t.Run("database_error_handling", func(t *testing.T) {
|
||||
// After our fix, database errors should:
|
||||
// 1. Be logged with s.logger.Error()
|
||||
// 2. Send doAckSimpleFail()
|
||||
// 3. Return immediately
|
||||
// 4. NOT send doAckSimpleSucceed() (the bug we fixed)
|
||||
|
||||
// This test documents the expected behavior
|
||||
})
|
||||
|
||||
t.Run("serialization_error_handling", func(t *testing.T) {
|
||||
// Test that serialization errors are handled gracefully
|
||||
emptyItems := []mhfitem.MHFItemStack{}
|
||||
serialized := mhfitem.SerializeWarehouseItems(emptyItems)
|
||||
|
||||
// Should handle empty gracefully
|
||||
if serialized == nil {
|
||||
t.Error("serialization of empty items should not return nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkWarehouseSerialization benchmarks warehouse serialization performance
|
||||
func BenchmarkWarehouseSerialization(b *testing.B) {
|
||||
items := []mhfitem.MHFItemStack{
|
||||
{Item: mhfitem.MHFItem{ItemID: 1}, Quantity: 10},
|
||||
{Item: mhfitem.MHFItem{ItemID: 2}, Quantity: 20},
|
||||
{Item: mhfitem.MHFItem{ItemID: 3}, Quantity: 30},
|
||||
{Item: mhfitem.MHFItem{ItemID: 4}, Quantity: 40},
|
||||
{Item: mhfitem.MHFItem{ItemID: 5}, Quantity: 50},
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = mhfitem.SerializeWarehouseItems(items)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWarehouseEquipmentMerge benchmarks equipment merge performance
|
||||
func BenchmarkWarehouseEquipmentMerge(b *testing.B) {
|
||||
oldEquip := make([]mhfitem.MHFEquipment, 50)
|
||||
for i := range oldEquip {
|
||||
oldEquip[i] = mhfitem.MHFEquipment{
|
||||
ItemID: uint16(100 + i),
|
||||
WarehouseID: uint32(i + 1),
|
||||
}
|
||||
}
|
||||
|
||||
newEquip := make([]mhfitem.MHFEquipment, 10)
|
||||
for i := range newEquip {
|
||||
newEquip[i] = mhfitem.MHFEquipment{
|
||||
ItemID: uint16(200 + i),
|
||||
WarehouseID: uint32(i + 1),
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var finalEquip []mhfitem.MHFEquipment
|
||||
oEquips := oldEquip
|
||||
|
||||
for _, uEquip := range newEquip {
|
||||
exists := false
|
||||
for j := range oEquips {
|
||||
if oEquips[j].WarehouseID == uEquip.WarehouseID {
|
||||
exists = true
|
||||
oEquips[j].ItemID = uEquip.ItemID
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
finalEquip = append(finalEquip, uEquip)
|
||||
}
|
||||
}
|
||||
|
||||
for _, oEquip := range oEquips {
|
||||
if oEquip.ItemID > 0 {
|
||||
finalEquip = append(finalEquip, oEquip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user