Implement Autonomous Mode Filtering in Robot API
- Added support for filtering robots by `autonomous_mode` in the ListRobots API. - Enhanced ListQuery structure to include an optional `AutonomousMode` field. - Updated listRobotsFromDB function to apply the autonomous mode filter based on the query. - Created new test cases to validate the filtering functionality for both autonomous and on-demand robots. - Revised related OpenAPI endpoints and frontend integration to accommodate the new filtering options.
This commit is contained in:
parent
6f93175a46
commit
bb7638f1e5
6 changed files with 296 additions and 60 deletions
|
|
@ -205,6 +205,75 @@ func TestAPIRobotQueryWithData(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestListRobotsAutonomousModeFilter tests the autonomous_mode filter
|
||||||
|
func TestListRobotsAutonomousModeFilter(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping integration test")
|
||||||
|
}
|
||||||
|
|
||||||
|
testutils.Prepare(t)
|
||||||
|
defer testutils.Clean(t)
|
||||||
|
|
||||||
|
cleanupAPITestRobots(t)
|
||||||
|
defer cleanupAPITestRobots(t)
|
||||||
|
|
||||||
|
// Setup: Create robots with different autonomous_mode settings
|
||||||
|
setupAPITestRobotWithMode(t, "robot_api_auto_001", "team_api_mode", true) // autonomous
|
||||||
|
setupAPITestRobotWithMode(t, "robot_api_auto_002", "team_api_mode", true) // autonomous
|
||||||
|
setupAPITestRobotWithMode(t, "robot_api_demand_001", "team_api_mode", false) // on-demand
|
||||||
|
|
||||||
|
ctx := types.NewContext(context.Background(), nil)
|
||||||
|
|
||||||
|
t.Run("ListRobots returns all robots when autonomous_mode is nil", func(t *testing.T) {
|
||||||
|
result, err := api.ListRobots(ctx, &api.ListQuery{
|
||||||
|
TeamID: "team_api_mode",
|
||||||
|
Page: 1,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
|
||||||
|
// Should have all 3 robots
|
||||||
|
assert.Equal(t, 3, result.Total)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListRobots filters by autonomous_mode=true", func(t *testing.T) {
|
||||||
|
autonomousMode := true
|
||||||
|
result, err := api.ListRobots(ctx, &api.ListQuery{
|
||||||
|
TeamID: "team_api_mode",
|
||||||
|
AutonomousMode: &autonomousMode,
|
||||||
|
Page: 1,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
|
||||||
|
// Should have only 2 autonomous robots
|
||||||
|
assert.Equal(t, 2, result.Total)
|
||||||
|
for _, robot := range result.Data {
|
||||||
|
assert.True(t, robot.AutonomousMode, "All returned robots should be autonomous")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListRobots filters by autonomous_mode=false", func(t *testing.T) {
|
||||||
|
autonomousMode := false
|
||||||
|
result, err := api.ListRobots(ctx, &api.ListQuery{
|
||||||
|
TeamID: "team_api_mode",
|
||||||
|
AutonomousMode: &autonomousMode,
|
||||||
|
Page: 1,
|
||||||
|
PageSize: 10,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, result)
|
||||||
|
|
||||||
|
// Should have only 1 on-demand robot
|
||||||
|
assert.Equal(t, 1, result.Total)
|
||||||
|
for _, robot := range result.Data {
|
||||||
|
assert.False(t, robot.AutonomousMode, "All returned robots should be on-demand")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TestAPIExecutionQueryWithData tests execution query APIs with real data
|
// TestAPIExecutionQueryWithData tests execution query APIs with real data
|
||||||
func TestAPIExecutionQueryWithData(t *testing.T) {
|
func TestAPIExecutionQueryWithData(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
|
|
@ -377,6 +446,44 @@ func TestAPITriggerWithData(t *testing.T) {
|
||||||
|
|
||||||
// ==================== Helper Functions ====================
|
// ==================== Helper Functions ====================
|
||||||
|
|
||||||
|
// setupAPITestRobotWithMode creates a test robot with specific autonomous_mode setting
|
||||||
|
func setupAPITestRobotWithMode(t *testing.T, memberID, teamID string, autonomousMode bool) {
|
||||||
|
m := model.Select("__yao.member")
|
||||||
|
tableName := m.MetaData.Table.Name
|
||||||
|
qb := capsule.Query()
|
||||||
|
|
||||||
|
robotConfig := map[string]interface{}{
|
||||||
|
"identity": map[string]interface{}{
|
||||||
|
"role": "API Test Robot",
|
||||||
|
"duties": []string{"Testing API functions"},
|
||||||
|
},
|
||||||
|
"quota": map[string]interface{}{
|
||||||
|
"max": 5,
|
||||||
|
"queue": 20,
|
||||||
|
"priority": 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
configJSON, _ := json.Marshal(robotConfig)
|
||||||
|
|
||||||
|
err := qb.Table(tableName).Insert([]map[string]interface{}{
|
||||||
|
{
|
||||||
|
"member_id": memberID,
|
||||||
|
"team_id": teamID,
|
||||||
|
"member_type": "robot",
|
||||||
|
"display_name": "API Test Robot " + memberID,
|
||||||
|
"system_prompt": "You are an API test robot.",
|
||||||
|
"status": "active",
|
||||||
|
"role_id": "member",
|
||||||
|
"autonomous_mode": autonomousMode,
|
||||||
|
"robot_status": "idle",
|
||||||
|
"robot_config": string(configJSON),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to insert robot %s: %v", memberID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// setupAPITestRobot creates a test robot in the database
|
// setupAPITestRobot creates a test robot in the database
|
||||||
func setupAPITestRobot(t *testing.T, memberID, teamID string) {
|
func setupAPITestRobot(t *testing.T, memberID, teamID string) {
|
||||||
m := model.Select("__yao.member")
|
m := model.Select("__yao.member")
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,6 @@ func listRobotsFromDB(query *ListQuery) (*ListResult, error) {
|
||||||
// Build where conditions
|
// Build where conditions
|
||||||
wheres := []model.QueryWhere{
|
wheres := []model.QueryWhere{
|
||||||
{Column: "member_type", Value: "robot"},
|
{Column: "member_type", Value: "robot"},
|
||||||
{Column: "autonomous_mode", Value: true},
|
|
||||||
{Column: "status", Value: "active"},
|
{Column: "status", Value: "active"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,6 +184,9 @@ func listRobotsFromDB(query *ListQuery) (*ListResult, error) {
|
||||||
Value: "%" + query.Keywords + "%",
|
Value: "%" + query.Keywords + "%",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if query.AutonomousMode != nil {
|
||||||
|
wheres = append(wheres, model.QueryWhere{Column: "autonomous_mode", Value: *query.AutonomousMode})
|
||||||
|
}
|
||||||
|
|
||||||
// Build order
|
// Build order
|
||||||
orders := []model.QueryOrder{}
|
orders := []model.QueryOrder{}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ type ListQuery struct {
|
||||||
Status types.RobotStatus `json:"status,omitempty"`
|
Status types.RobotStatus `json:"status,omitempty"`
|
||||||
Keywords string `json:"keywords,omitempty"`
|
Keywords string `json:"keywords,omitempty"`
|
||||||
ClockMode types.ClockMode `json:"clock_mode,omitempty"`
|
ClockMode types.ClockMode `json:"clock_mode,omitempty"`
|
||||||
|
AutonomousMode *bool `json:"autonomous_mode,omitempty"` // nil=all, true=autonomous only, false=on-demand only
|
||||||
Page int `json:"page,omitempty"`
|
Page int `json:"page,omitempty"`
|
||||||
PageSize int `json:"pagesize,omitempty"`
|
PageSize int `json:"pagesize,omitempty"`
|
||||||
Order string `json:"order,omitempty"`
|
Order string `json:"order,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
Backend → SDK → Page Integration
|
Backend → SDK → Page Integration
|
||||||
└─ List, Get, Create, Update, Delete robots
|
└─ List, Get, Create, Update, Delete robots
|
||||||
|
|
||||||
🟡 Phase 1-FE: Frontend Integration ⬜ [Current]
|
✅ Phase 1-FE: Frontend Integration ✅ [Completed]
|
||||||
└─ Implement SDK (openapi/robot.ts)
|
└─ SDK (openapi/robot.ts) ✅
|
||||||
└─ Page Integration (Robot list, detail, create, edit, delete)
|
└─ Page Integration (Robot list, detail, create, edit, delete) ✅
|
||||||
|
└─ UI/UX (CreatureLoading, bubble animations) ✅
|
||||||
|
|
||||||
🟢 Phase 2: Execution Management
|
🟢 Phase 2: Execution Management
|
||||||
Backend → SDK → Page Integration
|
Backend → SDK → Page Integration
|
||||||
|
|
@ -177,53 +178,92 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🟡 Phase 1-FE: Frontend Integration ⬜ [Current]
|
## ✅ Phase 1-FE: Frontend Integration ✅ [Completed]
|
||||||
|
|
||||||
**Goal:** Implement frontend SDK and integrate pages to validate Phase 1 deliverables
|
**Goal:** Implement frontend SDK and integrate pages to validate Phase 1 deliverables
|
||||||
**Status:** ⬜ Not Started
|
**Status:** ✅ Completed
|
||||||
|
|
||||||
### 1-FE.1 SDK Implementation ⬜
|
### 1-FE.1 SDK Implementation ✅
|
||||||
|
|
||||||
> Location: `cui/packages/cui/openapi/robot.ts`
|
> Location: `cui/packages/cui/openapi/agent/robot/`
|
||||||
|
|
||||||
- [ ] Create `robot.ts` - Robot API SDK
|
- [x] Create `robot/types.ts` - TypeScript types for Robot API
|
||||||
- [ ] `listRobots(params)` - GET /v1/agent/robots
|
- [x] `RobotFilter` - filter options for listing (including `autonomous_mode`)
|
||||||
- [ ] `getRobot(id)` - GET /v1/agent/robots/:id
|
- [x] `Robot` - robot data structure
|
||||||
- [ ] `getRobotStatus(id)` - GET /v1/agent/robots/:id/status
|
- [x] `RobotStatusResponse` - runtime status
|
||||||
- [ ] `createRobot(data)` - POST /v1/agent/robots
|
- [x] `RobotCreateRequest` / `RobotUpdateRequest` - CRUD requests
|
||||||
- [ ] `updateRobot(id, data)` - PUT /v1/agent/robots/:id
|
- [x] `RobotDeleteResponse` - delete response
|
||||||
- [ ] `deleteRobot(id)` - DELETE /v1/agent/robots/:id
|
- [x] Create `robot/robots.ts` - Robot API SDK class (`AgentRobots`)
|
||||||
- [ ] Add TypeScript types for request/response
|
- [x] `List(filter)` - GET /v1/agent/robots
|
||||||
- [ ] Export from `openapi/index.ts`
|
- [x] `Get(id)` - GET /v1/agent/robots/:id
|
||||||
|
- [x] `GetStatus(id)` - GET /v1/agent/robots/:id/status
|
||||||
|
- [x] `Create(data)` - POST /v1/agent/robots
|
||||||
|
- [x] `Update(id, data)` - PUT /v1/agent/robots/:id
|
||||||
|
- [x] `Delete(id)` - DELETE /v1/agent/robots/:id
|
||||||
|
- [x] Create `robot/index.ts` - exports
|
||||||
|
- [x] Update `agent/api.ts` - add `robots` property to Agent class
|
||||||
|
- [x] Update `agent/index.ts` - export robot module
|
||||||
|
- [x] Linter check passed
|
||||||
|
|
||||||
### 1-FE.2 Page Integration ⬜
|
### 1-FE.2 Page Integration ✅
|
||||||
|
|
||||||
> Location: `cui/packages/cui/pages/robot/`
|
> Location: `cui/packages/cui/pages/mission-control/`
|
||||||
|
|
||||||
- [ ] Robot List Page
|
- [x] Create `useRobots` hook for API calls
|
||||||
- [ ] Replace mock data with `listRobots()` API
|
- [x] `listRobots(filter)` - list robots with pagination
|
||||||
- [ ] Implement pagination
|
- [x] `getRobot(id)` - get single robot
|
||||||
- [ ] Implement filters (status, keywords, team)
|
- [x] `getRobotStatus(id)` - get runtime status
|
||||||
- [ ] Robot Detail Page
|
- [x] `createRobot(data)` - create robot
|
||||||
- [ ] Fetch robot via `getRobot(id)`
|
- [x] `updateRobot(id, data)` - update robot
|
||||||
- [ ] Display robot status via `getRobotStatus(id)`
|
- [x] `deleteRobot(id)` - delete robot
|
||||||
- [ ] Create Robot
|
- [x] Error handling and loading state
|
||||||
- [ ] Form validation
|
- [x] Robot List Page (`mission-control/index.tsx`)
|
||||||
- [ ] Call `createRobot()` API
|
- [x] Replace mock data with `listRobots()` API (fallback to mock)
|
||||||
- [ ] Handle success/error
|
- [x] Fetch status for each robot via `getRobotStatus()`
|
||||||
- [ ] Edit Robot
|
- [x] Refresh list after robot created/updated/deleted
|
||||||
- [ ] Pre-populate form with existing data
|
- [x] Empty state with "Create Agent" button (with bubble animation)
|
||||||
- [ ] Call `updateRobot()` API
|
- [ ] Implement pagination (TODO: Phase 2)
|
||||||
- [ ] Delete Robot
|
- [ ] Implement filters (status, keywords, team) (TODO: Phase 2)
|
||||||
- [ ] Confirmation dialog
|
- [x] Robot Detail Modal (`AgentModal`)
|
||||||
- [ ] Call `deleteRobot()` API
|
- [x] Real-time status refresh via `getRobotStatus(id)`
|
||||||
- [ ] Handle running execution conflict (409)
|
- [x] Auto-refresh every 10 seconds while modal open
|
||||||
|
- [x] Merge real-time status with robot data
|
||||||
|
- [x] Create Robot (`AddAgentModal`)
|
||||||
|
- [x] Call `createRobot()` API
|
||||||
|
- [x] Handle success/error messages
|
||||||
|
- [x] Form validation (existing)
|
||||||
|
- [x] Load email domains, managers, agents, MCP servers from API
|
||||||
|
- [x] Edit Robot (`ConfigTab` in `AgentModal`)
|
||||||
|
- [x] Load robot data from API (`getRobot()`)
|
||||||
|
- [x] Load email domains, managers, roles from Team API
|
||||||
|
- [x] Load agents and MCP servers from API
|
||||||
|
- [x] Pre-populate form with existing data
|
||||||
|
- [x] Call `updateRobot()` API with `robot_config.clock` for schedule
|
||||||
|
- [x] Handle success/error messages
|
||||||
|
- [x] Work Schedule panel saves correctly
|
||||||
|
- [x] Delete Robot (`AdvancedPanel` in `ConfigTab`)
|
||||||
|
- [x] Confirmation dialog with name input
|
||||||
|
- [x] Call `deleteRobot()` API
|
||||||
|
- [x] Handle running execution conflict (409)
|
||||||
|
- [x] Refresh list after deletion
|
||||||
|
|
||||||
### 1-FE.3 Verification ⬜
|
### 1-FE.3 UI/UX Enhancements ✅
|
||||||
|
|
||||||
- [ ] E2E test: Create → List → Get → Update → Delete
|
- [x] `CreatureLoading` component with organic animations
|
||||||
- [ ] Permission test: Personal user vs Team user
|
- [x] Breathing aura, floating creature, orbit ring, particles
|
||||||
- [ ] Error handling: 400, 403, 404, 409, 500
|
- [x] Three sizes: small, medium, large
|
||||||
|
- [x] Used in ConfigTab, ResultsTab, HistoryTab
|
||||||
|
- [x] Empty state "Create Agent" button with bubble animation
|
||||||
|
- [x] Cyan, purple, pink glowing bubbles rising
|
||||||
|
- [x] CSS variable compliance (`--color_mission_button_text`)
|
||||||
|
- [x] Consistent loading animations across all tabs
|
||||||
|
|
||||||
|
### 1-FE.4 Verification ✅
|
||||||
|
|
||||||
|
- [x] Manual test: Create → List → Get → Update → Delete
|
||||||
|
- [ ] E2E automated test (TODO: Phase 3)
|
||||||
|
- [x] Permission test: Personal user vs Team user (manual tested)
|
||||||
|
- [x] Error handling: 400, 403, 404, 409, 500
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -579,8 +619,8 @@ yao/openapi/tests/robot/
|
||||||
|
|
||||||
| Phase | Risk | Backend | Frontend | Description |
|
| Phase | Risk | Backend | Frontend | Description |
|
||||||
|-------|------|---------|----------|-------------|
|
|-------|------|---------|----------|-------------|
|
||||||
| 1. Core CRUD | 🟢 | ✅ | ⬜ | Robot CRUD endpoints |
|
| 1. Core CRUD | 🟢 | ✅ | ✅ | Robot CRUD endpoints |
|
||||||
| 1-FE Frontend Integration | 🟢 | - | 🟡 | **Current**: SDK + Page Integration |
|
| 1-FE Frontend Integration | 🟢 | - | ✅ | SDK ✅, Page Integration ✅, UI/UX ✅ |
|
||||||
| 2. Execution | 🟢 | ⬜ | ⬜ | Execution listing, control, trigger |
|
| 2. Execution | 🟢 | ⬜ | ⬜ | Execution listing, control, trigger |
|
||||||
| 3. Results/Activities | 🟢 | ⬜ | ⬜ | Deliverables and activity feed |
|
| 3. Results/Activities | 🟢 | ⬜ | ⬜ | Deliverables and activity feed |
|
||||||
| 4. i18n | 🟢 | ⬜ | ⬜ | Locale parameter support |
|
| 4. i18n | 🟢 | ⬜ | ⬜ | Locale parameter support |
|
||||||
|
|
@ -719,21 +759,36 @@ import (
|
||||||
|
|
||||||
**Execute immediately after each phase backend completion:**
|
**Execute immediately after each phase backend completion:**
|
||||||
|
|
||||||
1. **SDK Implementation** - `cui/packages/cui/openapi/robot.ts`
|
1. **SDK Implementation** - `cui/packages/cui/openapi/agent/robot/`
|
||||||
2. **Type Definitions** - TypeScript request/response types
|
2. **Type Definitions** - TypeScript request/response types
|
||||||
3. **Page Integration** - Replace mock data, call real APIs
|
3. **Hook Implementation** - `cui/packages/cui/hooks/useRobots.ts`
|
||||||
4. **E2E Verification** - Full flow testing
|
4. **Page Integration** - Replace mock data, call real APIs
|
||||||
|
5. **E2E Verification** - Full flow testing
|
||||||
|
|
||||||
**File Locations:**
|
**File Locations:**
|
||||||
```
|
```
|
||||||
cui/packages/cui/
|
cui/packages/cui/
|
||||||
├── openapi/
|
├── openapi/
|
||||||
│ ├── robot.ts # Robot API SDK
|
│ └── agent/
|
||||||
│ └── index.ts # Export all APIs
|
│ └── robot/
|
||||||
└── pages/robot/
|
│ ├── types.ts # TypeScript types
|
||||||
├── index.tsx # Robot list page
|
│ ├── robots.ts # AgentRobots SDK class
|
||||||
├── [id].tsx # Robot detail page
|
│ └── index.ts # Exports
|
||||||
└── components/ # Shared components
|
├── hooks/
|
||||||
|
│ └── useRobots.ts # React hook for robot API calls
|
||||||
|
├── styles/
|
||||||
|
│ └── preset/
|
||||||
|
│ └── vars.less # CSS variables (--color_mission_button_text)
|
||||||
|
└── pages/
|
||||||
|
└── mission-control/
|
||||||
|
├── index.tsx # Robot list (grid) page
|
||||||
|
├── index.less # Styles with bubble animations
|
||||||
|
└── components/
|
||||||
|
├── AgentModal/ # Robot detail modal
|
||||||
|
├── AddAgentModal/ # Create robot modal
|
||||||
|
└── CreatureLoading/ # Branded loading component
|
||||||
|
├── index.tsx
|
||||||
|
└── index.less
|
||||||
```
|
```
|
||||||
|
|
||||||
### Incremental Deployment
|
### Incremental Deployment
|
||||||
|
|
@ -742,7 +797,7 @@ Each phase independently deliverable:
|
||||||
|
|
||||||
| Phase | Backend | Frontend | Verifiable Features |
|
| Phase | Backend | Frontend | Verifiable Features |
|
||||||
|-------|---------|----------|---------------------|
|
|-------|---------|----------|---------------------|
|
||||||
| 1 | ✅ | 🟡 Current | Robot CRUD basic management |
|
| 1 | ✅ | ✅ | Robot CRUD basic management |
|
||||||
| 2 | ⬜ | ⬜ | Execution list/control/trigger |
|
| 2 | ⬜ | ⬜ | Execution list/control/trigger |
|
||||||
| 3 | ⬜ | ⬜ | Results/Activities viewing |
|
| 3 | ⬜ | ⬜ | Results/Activities viewing |
|
||||||
| 4 | ⬜ | ⬜ | Multi-language support |
|
| 4 | ⬜ | ⬜ | Multi-language support |
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ func ListRobots(c *gin.Context) {
|
||||||
requestedTeamID := strings.TrimSpace(c.Query("team_id"))
|
requestedTeamID := strings.TrimSpace(c.Query("team_id"))
|
||||||
status := strings.TrimSpace(c.Query("status"))
|
status := strings.TrimSpace(c.Query("status"))
|
||||||
keywords := strings.TrimSpace(c.Query("keywords"))
|
keywords := strings.TrimSpace(c.Query("keywords"))
|
||||||
|
autonomousModeStr := strings.TrimSpace(c.Query("autonomous_mode"))
|
||||||
|
|
||||||
// Apply permission-based filtering
|
// Apply permission-based filtering
|
||||||
// This ensures users only see robots they have access to:
|
// This ensures users only see robots they have access to:
|
||||||
|
|
@ -55,6 +56,14 @@ func ListRobots(c *gin.Context) {
|
||||||
if status != "" {
|
if status != "" {
|
||||||
query.Status = robottypes.RobotStatus(status)
|
query.Status = robottypes.RobotStatus(status)
|
||||||
}
|
}
|
||||||
|
// Parse autonomous_mode filter: "true" or "false" to filter, empty/other to show all
|
||||||
|
if autonomousModeStr == "true" {
|
||||||
|
autonomousMode := true
|
||||||
|
query.AutonomousMode = &autonomousMode
|
||||||
|
} else if autonomousModeStr == "false" {
|
||||||
|
autonomousMode := false
|
||||||
|
query.AutonomousMode = &autonomousMode
|
||||||
|
}
|
||||||
|
|
||||||
// Create robot context
|
// Create robot context
|
||||||
ctx := &robottypes.Context{}
|
ctx := &robottypes.Context{}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,68 @@ func TestListRobots(t *testing.T) {
|
||||||
assert.Equal(t, float64(5), response["pagesize"])
|
assert.Equal(t, float64(5), response["pagesize"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("ListRobotsWithAutonomousModeFilter", func(t *testing.T) {
|
||||||
|
// Test with autonomous_mode=true
|
||||||
|
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots?autonomous_mode=true", 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 response structure
|
||||||
|
assert.Contains(t, response, "data")
|
||||||
|
assert.Contains(t, response, "total")
|
||||||
|
|
||||||
|
// If there are robots, verify they are all autonomous
|
||||||
|
if data, ok := response["data"].([]interface{}); ok && len(data) > 0 {
|
||||||
|
for _, item := range data {
|
||||||
|
if robot, ok := item.(map[string]interface{}); ok {
|
||||||
|
assert.True(t, robot["autonomous_mode"].(bool), "All robots should have autonomous_mode=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ListRobotsWithAutonomousModeFalse", func(t *testing.T) {
|
||||||
|
// Test with autonomous_mode=false
|
||||||
|
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots?autonomous_mode=false", 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 response structure
|
||||||
|
assert.Contains(t, response, "data")
|
||||||
|
assert.Contains(t, response, "total")
|
||||||
|
|
||||||
|
// If there are robots, verify they are all on-demand (not autonomous)
|
||||||
|
if data, ok := response["data"].([]interface{}); ok && len(data) > 0 {
|
||||||
|
for _, item := range data {
|
||||||
|
if robot, ok := item.(map[string]interface{}); ok {
|
||||||
|
assert.False(t, robot["autonomous_mode"].(bool), "All robots should have autonomous_mode=false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("ListRobotsUnauthorized", func(t *testing.T) {
|
t.Run("ListRobotsUnauthorized", func(t *testing.T) {
|
||||||
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
|
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue