Agent inbounds defined centrally store an empty originNodeGuid, and inbounds re-homed from a panel node keep the previous host's GUID, so the inbounds page looked the agent's online set up under a key it is never filed under. GetInboundsSlim now annotates agent-hosted inbounds at read time with the node's effective attribution key (the key SetAgentOnlineClients files onlines under).
96 lines
3.5 KiB
Go
96 lines
3.5 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
// The inbounds page looks a node's online set up under the inbound's
|
|
// originNodeGuid (falling back to node:{id}). Agent inbounds are defined
|
|
// centrally: a fresh one stores no origin GUID, and one re-homed from a
|
|
// panel node keeps the GUID the snapshot merge stamped for its PREVIOUS
|
|
// host — while the agent's onlines are filed under the agent node's own
|
|
// effective key. The slim list must therefore stamp agent-hosted inbounds
|
|
// with the hosting node's effective key at read time, or their clients
|
|
// never show as online on the inbounds page (production: every converted
|
|
// agent node was affected). Traditional inbounds' stored origins are
|
|
// chain attribution (#4983) and must pass through untouched.
|
|
func TestGetInboundsSlim_AnnotatesAgentOriginGuid(t *testing.T) {
|
|
setupConflictDB(t)
|
|
db := database.GetDB()
|
|
svc := InboundService{}
|
|
|
|
const agentNodeID = 8201
|
|
const tradNodeID = 8202
|
|
const userID = 1
|
|
|
|
if err := db.Create(&model.Node{Id: agentNodeID, Name: "agent-node", Address: "10.0.8.1"}).Error; err != nil {
|
|
t.Fatalf("create agent node: %v", err)
|
|
}
|
|
if err := db.Create(&model.Node{Id: tradNodeID, Name: "trad-node", Address: "10.0.8.2", Port: 2053, ApiToken: "t", Guid: "trad-guid-8202"}).Error; err != nil {
|
|
t.Fatalf("create trad node: %v", err)
|
|
}
|
|
// The agent binding is what makes the node "agent-managed".
|
|
agentID := agentNodeID
|
|
if err := db.Create(&model.AgentNode{
|
|
TokenHash: fmt.Sprintf("%064d", agentNodeID),
|
|
Name: "agent-node",
|
|
NodeID: &agentID,
|
|
}).Error; err != nil {
|
|
t.Fatalf("create agent binding: %v", err)
|
|
}
|
|
|
|
mkInbound := func(tag string, nodeID *int, origin string) {
|
|
ib := &model.Inbound{
|
|
UserId: userID,
|
|
Tag: tag,
|
|
Enable: true,
|
|
Port: 443,
|
|
Protocol: model.VLESS,
|
|
Settings: `{"clients":[{"email":"a@example.com","enable":true}]}`,
|
|
NodeID: nodeID,
|
|
OriginNodeGuid: origin,
|
|
}
|
|
if err := db.Create(ib).Error; err != nil {
|
|
t.Fatalf("create inbound %s: %v", tag, err)
|
|
}
|
|
}
|
|
agentIDCopy := agentNodeID
|
|
tradIDCopy := tradNodeID
|
|
mkInbound("agent-stale", &agentIDCopy, "guid-of-previous-panel-host")
|
|
mkInbound("agent-fresh", &agentIDCopy, "")
|
|
mkInbound("trad-synced", &tradIDCopy, "trad-guid-8202")
|
|
|
|
slim, err := svc.GetInboundsSlim(userID)
|
|
if err != nil {
|
|
t.Fatalf("GetInboundsSlim: %v", err)
|
|
}
|
|
byTag := make(map[string]*model.Inbound, len(slim))
|
|
for _, ib := range slim {
|
|
byTag[ib.Tag] = ib
|
|
}
|
|
|
|
wantKey := fmt.Sprintf("node:%d", agentNodeID)
|
|
if got := byTag["agent-stale"].OriginNodeGuid; got != wantKey {
|
|
t.Errorf("agent-stale originNodeGuid = %q, want %q (stale host GUID healed to the agent's key)", got, wantKey)
|
|
}
|
|
if got := byTag["agent-fresh"].OriginNodeGuid; got != wantKey {
|
|
t.Errorf("agent-fresh originNodeGuid = %q, want %q", got, wantKey)
|
|
}
|
|
if got := byTag["trad-synced"].OriginNodeGuid; got != "trad-guid-8202" {
|
|
t.Errorf("trad-synced originNodeGuid = %q, want stored GUID untouched", got)
|
|
}
|
|
|
|
// Read-time only: the stored value must not be rewritten.
|
|
var stored model.Inbound
|
|
if err := db.Where("tag = ?", "agent-stale").First(&stored).Error; err != nil {
|
|
t.Fatalf("reload agent-stale: %v", err)
|
|
}
|
|
if stored.OriginNodeGuid != "guid-of-previous-panel-host" {
|
|
t.Errorf("stored origin_node_guid = %q, want the stale value preserved (annotation is read-time only)", stored.OriginNodeGuid)
|
|
}
|
|
}
|