Enhance ListRobots API to Include Runtime Status
- Added concurrent fetching of runtime status for each robot in the ListRobots function, improving response efficiency. - Updated the Response struct to include new fields for runtime status: Running, MaxRunning, LastRun, and NextRun, optimizing dashboard display. - Implemented unit tests to verify the inclusion of runtime status fields in the ListRobots response, ensuring accurate data representation for users.
This commit is contained in:
parent
3ef536c1e7
commit
6fa808c875
3 changed files with 83 additions and 4 deletions
|
|
@ -3,6 +3,7 @@ package robot
|
|||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yaoapp/kun/log"
|
||||
|
|
@ -80,11 +81,30 @@ func ListRobots(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// Convert to HTTP response format
|
||||
robots := make([]*Response, 0, len(result.Data))
|
||||
for _, r := range result.Data {
|
||||
robots = append(robots, newResponseFromRobot(r))
|
||||
// Convert to HTTP response format with runtime status
|
||||
robots := make([]*Response, len(result.Data))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i, r := range result.Data {
|
||||
wg.Add(1)
|
||||
go func(idx int, robot *robottypes.Robot) {
|
||||
defer wg.Done()
|
||||
resp := newResponseFromRobot(robot)
|
||||
|
||||
// Fetch runtime status for each robot
|
||||
if status, err := robotapi.GetRobotStatus(ctx, robot.MemberID); err == nil && status != nil {
|
||||
resp.Running = status.Running
|
||||
resp.MaxRunning = status.MaxRunning
|
||||
resp.LastRun = status.LastRun
|
||||
resp.NextRun = status.NextRun
|
||||
// Use runtime status instead of stored status
|
||||
resp.RobotStatus = string(status.Status)
|
||||
}
|
||||
|
||||
robots[idx] = resp
|
||||
}(i, r)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
resp := &ListResponse{
|
||||
Data: robots,
|
||||
|
|
|
|||
|
|
@ -126,6 +126,12 @@ type Response struct {
|
|||
// Timestamps
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
|
||||
// Runtime Status (populated in list view for dashboard)
|
||||
Running int `json:"running"` // Current running executions count
|
||||
MaxRunning int `json:"max_running,omitempty"` // Maximum concurrent executions
|
||||
LastRun *time.Time `json:"last_run,omitempty"` // Last execution time
|
||||
NextRun *time.Time `json:"next_run,omitempty"` // Next scheduled run time
|
||||
}
|
||||
|
||||
// StatusResponse - runtime status response
|
||||
|
|
|
|||
|
|
@ -52,6 +52,15 @@ func TestListRobots(t *testing.T) {
|
|||
assert.Contains(t, response, "page")
|
||||
assert.Contains(t, response, "pagesize")
|
||||
assert.Contains(t, response, "total")
|
||||
|
||||
// Verify runtime status fields are included in robot items
|
||||
if data, ok := response["data"].([]interface{}); ok && len(data) > 0 {
|
||||
robot := data[0].(map[string]interface{})
|
||||
// Runtime status fields should be present (added for dashboard optimization)
|
||||
assert.Contains(t, robot, "running", "Robot should include running count")
|
||||
assert.Contains(t, robot, "max_running", "Robot should include max_running")
|
||||
// last_run and next_run are optional (omitempty)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ListRobotsWithPagination", func(t *testing.T) {
|
||||
|
|
@ -136,6 +145,50 @@ func TestListRobots(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("ListRobotsIncludesRuntimeStatus", func(t *testing.T) {
|
||||
// Verify that list response includes runtime status fields for dashboard optimization
|
||||
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
var response map[string]interface{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we have robots to test
|
||||
data, ok := response["data"].([]interface{})
|
||||
require.True(t, ok, "Response should have data array")
|
||||
|
||||
if len(data) > 0 {
|
||||
robot := data[0].(map[string]interface{})
|
||||
|
||||
// Runtime status fields (running is always present, defaults to 0)
|
||||
_, hasRunning := robot["running"]
|
||||
assert.True(t, hasRunning, "Robot should include 'running' field for dashboard")
|
||||
|
||||
// max_running should be present (with omitempty, only if > 0)
|
||||
// The field is returned by GetRobotStatus, so it should be there
|
||||
if maxRunning, ok := robot["max_running"]; ok {
|
||||
assert.GreaterOrEqual(t, maxRunning.(float64), float64(0), "max_running should be >= 0")
|
||||
}
|
||||
|
||||
// robot_status should reflect runtime status
|
||||
robotStatus, hasStatus := robot["robot_status"]
|
||||
assert.True(t, hasStatus, "Robot should include 'robot_status' field")
|
||||
if hasStatus {
|
||||
validStatuses := []string{"idle", "working", "paused", "error", "maintenance"}
|
||||
assert.Contains(t, validStatuses, robotStatus.(string), "robot_status should be a valid status")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ListRobotsUnauthorized", func(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue