package service import ( "testing" "github.com/mhsanaei/3x-ui/v3/internal/database" "github.com/mhsanaei/3x-ui/v3/internal/database/model" ) func makeInboundWithSubSortIndex(tag string, port int, subSortIndex int) *model.Inbound { return &model.Inbound{ UserId: 1, Tag: tag, Enable: true, Listen: "0.0.0.0", Port: port, Protocol: model.VLESS, StreamSettings: `{"network":"tcp"}`, Settings: `{"clients":[]}`, SubSortIndex: subSortIndex, } } // TestUpdateInbound_PersistsSubSortIndex verifies that UpdateInbound copies // SubSortIndex from the incoming update payload to the persisted row. func TestUpdateInbound_PersistsSubSortIndex(t *testing.T) { setupConflictDB(t) ib := makeInboundWithSubSortIndex("in-7001-tcp", 7001, 1) if err := database.GetDB().Create(ib).Error; err != nil { t.Fatalf("create inbound: %v", err) } update := *ib update.SubSortIndex = 7 svc := &InboundService{} got, _, err := svc.UpdateInbound(&update) if err != nil { t.Fatalf("UpdateInbound: %v", err) } if got.SubSortIndex != 7 { t.Fatalf("returned SubSortIndex = %d, want 7", got.SubSortIndex) } var reloaded model.Inbound if err := database.GetDB().First(&reloaded, ib.Id).Error; err != nil { t.Fatalf("reload: %v", err) } if reloaded.SubSortIndex != 7 { t.Fatalf("persisted SubSortIndex = %d, want 7", reloaded.SubSortIndex) } } // TestUpdateInbound_SubSortIndexZeroMapsToDefault verifies that 0 from clients // that predate the field is normalized to 1 instead of being stored. func TestUpdateInbound_SubSortIndexZeroMapsToDefault(t *testing.T) { setupConflictDB(t) ib := makeInboundWithSubSortIndex("in-7002-tcp", 7002, 5) if err := database.GetDB().Create(ib).Error; err != nil { t.Fatalf("create inbound: %v", err) } svc := &InboundService{} update := *ib update.SubSortIndex = 0 got, _, err := svc.UpdateInbound(&update) if err != nil { t.Fatalf("UpdateInbound: %v", err) } if got.SubSortIndex != 1 { t.Fatalf("returned SubSortIndex = %d, want 1", got.SubSortIndex) } var reloaded model.Inbound if err := database.GetDB().First(&reloaded, ib.Id).Error; err != nil { t.Fatalf("reload: %v", err) } if reloaded.SubSortIndex != 1 { t.Fatalf("persisted SubSortIndex = %d, want 1", reloaded.SubSortIndex) } } // TestUpdateInbound_PreservesNegativeSubSortIndex verifies that an explicitly // set negative index is stored (so it can sort ahead of the default of 1). func TestUpdateInbound_PreservesNegativeSubSortIndex(t *testing.T) { setupConflictDB(t) ib := makeInboundWithSubSortIndex("in-7004-tcp", 7004, 5) if err := database.GetDB().Create(ib).Error; err != nil { t.Fatalf("create inbound: %v", err) } svc := &InboundService{} update := *ib update.SubSortIndex = -1 got, _, err := svc.UpdateInbound(&update) if err != nil { t.Fatalf("UpdateInbound: %v", err) } if got.SubSortIndex != -1 { t.Fatalf("returned SubSortIndex = %d, want -1", got.SubSortIndex) } var reloaded model.Inbound if err := database.GetDB().First(&reloaded, ib.Id).Error; err != nil { t.Fatalf("reload: %v", err) } if reloaded.SubSortIndex != -1 { t.Fatalf("persisted SubSortIndex = %d, want -1", reloaded.SubSortIndex) } } // TestAddInbound_SubSortIndexClampedToMinimum verifies the same clamping on // the create path (an omitted form field binds to 0). func TestAddInbound_SubSortIndexClampedToMinimum(t *testing.T) { setupConflictDB(t) svc := &InboundService{} ib := makeInboundWithSubSortIndex("in-7003-tcp", 7003, 0) got, _, err := svc.AddInbound(ib) if err != nil { t.Fatalf("AddInbound: %v", err) } if got.SubSortIndex != 1 { t.Fatalf("returned SubSortIndex = %d, want 1", got.SubSortIndex) } var reloaded model.Inbound if err := database.GetDB().First(&reloaded, got.Id).Error; err != nil { t.Fatalf("reload: %v", err) } if reloaded.SubSortIndex != 1 { t.Fatalf("persisted SubSortIndex = %d, want 1", reloaded.SubSortIndex) } }