| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- package service
- import (
- "strings"
- "testing"
- "github.com/mhsanaei/3x-ui/v3/internal/database"
- "github.com/mhsanaei/3x-ui/v3/internal/database/model"
- "github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
- )
- func setupEnablePortTest(t *testing.T) {
- t.Helper()
- setupConflictDB(t)
- mgr := runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }})
- mgr.SetLocalRuntimeOverride(&fakeNodeRuntime{})
- runtime.SetManager(mgr)
- t.Cleanup(func() { runtime.SetManager(nil) })
- }
- func disableInboundRow(t *testing.T, id int) {
- t.Helper()
- if err := database.GetDB().Model(&model.Inbound{}).Where("id = ?", id).Update("enable", false).Error; err != nil {
- t.Fatalf("disable row %d: %v", id, err)
- }
- }
- // Saving a row while it is disabled skips every port guard, so enabling it later
- // was the one path that could still put two inbounds on one socket.
- func TestSetInboundEnableRefusesAPortAnotherEnabledInboundServes(t *testing.T) {
- setupEnablePortTest(t)
- seedInboundConflict(t, "holder", "0.0.0.0", 44431, model.VLESS, `{"network":"tcp"}`, `{}`)
- seedInboundConflict(t, "sleeper", "0.0.0.0", 44431, model.VLESS, `{"network":"tcp"}`, `{}`)
- sleeper := loadInboundByTag(t, "sleeper")
- disableInboundRow(t, sleeper.Id)
- _, err := (&InboundService{}).SetInboundEnable(sleeper.Id, true)
- if err == nil {
- t.Fatal("enabling a row onto a port another enabled inbound serves must be refused")
- }
- if !strings.Contains(err.Error(), "holder") {
- t.Fatalf("the refusal must name the row that owns the port; got %q", err)
- }
- if after := loadInboundByTag(t, "sleeper"); after.Enable {
- t.Fatal("a refused enable must not write the flag")
- }
- }
- // The enable path must keep the tcp/udp coexistence the rest of the guards
- // allow, or it would refuse half of the working setups out there.
- func TestSetInboundEnableAllowsTCPUDPCoexistence(t *testing.T) {
- setupEnablePortTest(t)
- seedInboundConflict(t, "udp-holder", "0.0.0.0", 44432, model.Hysteria, ``, `{}`)
- seedInboundConflict(t, "tcp-sleeper", "0.0.0.0", 44432, model.VLESS, `{"network":"tcp"}`, `{}`)
- sleeper := loadInboundByTag(t, "tcp-sleeper")
- disableInboundRow(t, sleeper.Id)
- if _, err := (&InboundService{}).SetInboundEnable(sleeper.Id, true); err != nil {
- t.Fatalf("a tcp inbound must be able to enable onto a udp-only row's port: %v", err)
- }
- if after := loadInboundByTag(t, "tcp-sleeper"); !after.Enable {
- t.Fatal("the row must be enabled")
- }
- }
- // Nodes run their own Xray, so a node row sharing a local port is legal and must
- // stay enableable.
- func TestSetInboundEnableAllowsANodeRowOnALocalPort(t *testing.T) {
- setupEnablePortTest(t)
- seedInboundConflict(t, "local-holder", "0.0.0.0", 44433, model.VLESS, `{"network":"tcp"}`, `{}`)
- node := &model.Node{Name: "n1", Address: "127.0.0.1", Port: 2096, Scheme: "https", Enable: true, Status: "online"}
- if err := database.GetDB().Create(node).Error; err != nil {
- t.Fatalf("seed node: %v", err)
- }
- seedInboundConflictNode(t, "node-row", "0.0.0.0", 44433, model.VLESS, `{"network":"tcp"}`, `{}`, &node.Id)
- row := loadInboundByTag(t, "node-row")
- disableInboundRow(t, row.Id)
- if _, err := (&InboundService{}).SetInboundEnable(row.Id, true); err != nil {
- t.Fatalf("a node row must be enableable regardless of a local row's port: %v", err)
- }
- }
|