package service import ( "context" "strings" "testing" "github.com/mhsanaei/3x-ui/v3/internal/database" "github.com/mhsanaei/3x-ui/v3/internal/database/model" ) // Item 20 (master side): UpdatePanels on an agent node records an update // intent on the bound agent row instead of pushing to a remote panel. The // intent targets the newest release tag (V-series) expressed as the // agent's A-series display version. func TestUpdatePanelsAgentIntent(t *testing.T) { setupConflictDB(t) db := database.GetDB() origFetch := fetchLatestReleaseTag fetchLatestReleaseTag = func(context.Context) (string, error) { return "V1.0.1", nil } t.Cleanup(func() { fetchLatestReleaseTag = origFetch }) node := &model.Node{Id: 7501, Name: "agent-upd", Address: "", Enable: true, Status: "online"} if err := db.Create(node).Error; err != nil { t.Fatalf("create node: %v", err) } ag := &model.AgentNode{ TokenHash: "hash-upd", Name: "agent-upd", NodeID: &node.Id, AgentVersion: "A1.0.0", } if err := db.Create(ag).Error; err != nil { t.Fatalf("create agent: %v", err) } svc := &NodeService{} results, err := svc.UpdatePanels([]int{node.Id}, false) if err != nil { t.Fatalf("UpdatePanels: %v", err) } if len(results) != 1 || !results[0].OK { t.Fatalf("results = %+v, want one OK", results) } var row model.AgentNode if err := db.First(&row, ag.Id).Error; err != nil { t.Fatal(err) } if row.UpdateState != "pending" || row.UpdateTarget != "A1.0.1" || row.UpdateTag != "V1.0.1" || row.UpdateRequestedAt == 0 { t.Fatalf("intent not recorded: %+v", row) } } func TestUpdatePanelsAgentAlreadyCurrent(t *testing.T) { setupConflictDB(t) db := database.GetDB() origFetch := fetchLatestReleaseTag fetchLatestReleaseTag = func(context.Context) (string, error) { return "V1.0.1", nil } t.Cleanup(func() { fetchLatestReleaseTag = origFetch }) node := &model.Node{Id: 7502, Name: "agent-cur", Address: "", Enable: true, Status: "online"} if err := db.Create(node).Error; err != nil { t.Fatalf("create node: %v", err) } ag := &model.AgentNode{ TokenHash: "hash-cur", Name: "agent-cur", NodeID: &node.Id, AgentVersion: "A1.0.1", } if err := db.Create(ag).Error; err != nil { t.Fatalf("create agent: %v", err) } svc := &NodeService{} results, err := svc.UpdatePanels([]int{node.Id}, false) if err != nil { t.Fatalf("UpdatePanels: %v", err) } if len(results) != 1 || results[0].OK || !strings.Contains(results[0].Error, "already up to date") { t.Fatalf("results = %+v, want not-OK already-up-to-date", results) } var row model.AgentNode if err := db.First(&row, ag.Id).Error; err != nil { t.Fatal(err) } if row.UpdateRequestedAt != 0 { t.Fatalf("no intent may be recorded for a current agent: %+v", row) } }