- 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.
606 lines
18 KiB
Go
606 lines
18 KiB
Go
package api_test
|
|
|
|
// Integration tests for the Robot Agent API
|
|
// These tests verify the complete API functionality with real database operations.
|
|
//
|
|
// Test Structure:
|
|
// - api_test.go: Core API integration tests (this file)
|
|
// - lifecycle_test.go: Start/Stop lifecycle tests
|
|
// - robot_test.go: Robot query tests
|
|
// - trigger_test.go: Trigger tests
|
|
// - execution_test.go: Execution query/control tests
|
|
//
|
|
// Test Data:
|
|
// All tests use real database records in __yao.member and agent_execution tables
|
|
// Test robot IDs are prefixed with "robot_api_" for easy cleanup
|
|
// Test execution IDs are prefixed with "exec_api_" for easy cleanup
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/yaoapp/gou/model"
|
|
"github.com/yaoapp/xun/capsule"
|
|
"github.com/yaoapp/yao/agent/robot/api"
|
|
"github.com/yaoapp/yao/agent/robot/store"
|
|
"github.com/yaoapp/yao/agent/robot/types"
|
|
"github.com/yaoapp/yao/agent/testutils"
|
|
)
|
|
|
|
// ==================== Full Lifecycle Integration Tests ====================
|
|
|
|
// TestAPIFullLifecycle tests the complete API workflow:
|
|
// Start → Create Robot → Query Robot → Trigger → Query Execution → Stop
|
|
func TestAPIFullLifecycle(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping integration test")
|
|
}
|
|
|
|
testutils.Prepare(t)
|
|
defer testutils.Clean(t)
|
|
|
|
// Cleanup test data
|
|
cleanupAPITestRobots(t)
|
|
cleanupAPITestExecutions(t)
|
|
defer cleanupAPITestRobots(t)
|
|
defer cleanupAPITestExecutions(t)
|
|
|
|
t.Run("complete workflow", func(t *testing.T) {
|
|
// 1. Setup: Create test robot in database
|
|
setupAPITestRobot(t, "robot_api_lifecycle_001", "team_api_001")
|
|
|
|
// 2. Start the API system
|
|
err := api.Start()
|
|
require.NoError(t, err)
|
|
assert.True(t, api.IsRunning())
|
|
defer api.Stop()
|
|
|
|
// 3. Query the robot via API
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
robot, err := api.GetRobot(ctx, "robot_api_lifecycle_001")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, robot)
|
|
assert.Equal(t, "robot_api_lifecycle_001", robot.MemberID)
|
|
assert.Equal(t, "team_api_001", robot.TeamID)
|
|
assert.Equal(t, "API Test Robot robot_api_lifecycle_001", robot.DisplayName)
|
|
|
|
// 4. Get robot status
|
|
status, err := api.GetRobotStatus(ctx, "robot_api_lifecycle_001")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, status)
|
|
assert.Equal(t, "robot_api_lifecycle_001", status.MemberID)
|
|
assert.Equal(t, types.RobotIdle, status.Status)
|
|
assert.Equal(t, 0, status.Running)
|
|
assert.Equal(t, 5, status.MaxRunning)
|
|
|
|
// 5. List robots
|
|
listResult, err := api.ListRobots(ctx, &api.ListQuery{
|
|
TeamID: "team_api_001",
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, listResult)
|
|
assert.GreaterOrEqual(t, listResult.Total, 1)
|
|
|
|
// Find our robot in the list
|
|
found := false
|
|
for _, r := range listResult.Data {
|
|
if r.MemberID == "robot_api_lifecycle_001" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, "Robot should be in list")
|
|
|
|
// 6. Trigger manual execution
|
|
triggerResult, err := api.TriggerManual(ctx, "robot_api_lifecycle_001", types.TriggerClock, nil)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, triggerResult)
|
|
assert.True(t, triggerResult.Accepted)
|
|
assert.NotEmpty(t, triggerResult.JobID)
|
|
|
|
// 7. Wait for execution to complete
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
// 8. Stop the system
|
|
err = api.Stop()
|
|
require.NoError(t, err)
|
|
assert.False(t, api.IsRunning())
|
|
})
|
|
}
|
|
|
|
// TestAPIRobotQueryWithData tests robot query APIs with real data
|
|
func TestAPIRobotQueryWithData(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 multiple robots
|
|
setupAPITestRobot(t, "robot_api_query_001", "team_api_query")
|
|
setupAPITestRobot(t, "robot_api_query_002", "team_api_query")
|
|
setupAPITestRobot(t, "robot_api_query_003", "team_api_other")
|
|
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
t.Run("GetRobot returns correct robot", func(t *testing.T) {
|
|
robot, err := api.GetRobot(ctx, "robot_api_query_001")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, robot)
|
|
|
|
assert.Equal(t, "robot_api_query_001", robot.MemberID)
|
|
assert.Equal(t, "team_api_query", robot.TeamID)
|
|
assert.Equal(t, "API Test Robot robot_api_query_001", robot.DisplayName)
|
|
assert.True(t, robot.AutonomousMode)
|
|
assert.Equal(t, types.RobotIdle, robot.Status)
|
|
})
|
|
|
|
t.Run("ListRobots filters by team", func(t *testing.T) {
|
|
result, err := api.ListRobots(ctx, &api.ListQuery{
|
|
TeamID: "team_api_query",
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should have at least 2 robots from team_api_query
|
|
// (might have more if other tests created robots in this team)
|
|
assert.GreaterOrEqual(t, result.Total, 2)
|
|
assert.GreaterOrEqual(t, len(result.Data), 2)
|
|
|
|
// Verify all returned robots are from the correct team
|
|
for _, robot := range result.Data {
|
|
assert.Equal(t, "team_api_query", robot.TeamID)
|
|
}
|
|
})
|
|
|
|
t.Run("ListRobots pagination works", func(t *testing.T) {
|
|
// Page 1 with size 1
|
|
result1, err := api.ListRobots(ctx, &api.ListQuery{
|
|
TeamID: "team_api_query",
|
|
Page: 1,
|
|
PageSize: 1,
|
|
})
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(result1.Data), 1, "Should have at least 1 robot on page 1")
|
|
|
|
// Page 2 with size 1
|
|
result2, err := api.ListRobots(ctx, &api.ListQuery{
|
|
TeamID: "team_api_query",
|
|
Page: 2,
|
|
PageSize: 1,
|
|
})
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(result2.Data), 1, "Should have at least 1 robot on page 2")
|
|
|
|
// Should be different robots
|
|
assert.NotEqual(t, result1.Data[0].MemberID, result2.Data[0].MemberID)
|
|
})
|
|
|
|
t.Run("ListRobots filters by keywords", func(t *testing.T) {
|
|
result, err := api.ListRobots(ctx, &api.ListQuery{
|
|
Keywords: "robot_api_query_001",
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should find at least 1 robot matching keywords
|
|
assert.GreaterOrEqual(t, result.Total, 1)
|
|
for _, robot := range result.Data {
|
|
assert.Contains(t, robot.DisplayName, "robot_api_query_001")
|
|
}
|
|
})
|
|
}
|
|
|
|
// 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
|
|
func TestAPIExecutionQueryWithData(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping integration test")
|
|
}
|
|
|
|
testutils.Prepare(t)
|
|
defer testutils.Clean(t)
|
|
|
|
cleanupAPITestExecutions(t)
|
|
defer cleanupAPITestExecutions(t)
|
|
|
|
// Setup: Create test executions
|
|
setupAPITestExecution(t, "exec_api_query_001", "member_api_exec", types.TriggerClock, types.ExecCompleted)
|
|
setupAPITestExecution(t, "exec_api_query_002", "member_api_exec", types.TriggerHuman, types.ExecRunning)
|
|
setupAPITestExecution(t, "exec_api_query_003", "member_api_exec", types.TriggerClock, types.ExecFailed)
|
|
setupAPITestExecution(t, "exec_api_query_004", "member_api_other", types.TriggerEvent, types.ExecCompleted)
|
|
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
t.Run("GetExecution returns correct execution", func(t *testing.T) {
|
|
exec, err := api.GetExecution(ctx, "exec_api_query_001")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, exec)
|
|
|
|
assert.Equal(t, "exec_api_query_001", exec.ID)
|
|
assert.Equal(t, "member_api_exec", exec.MemberID)
|
|
assert.Equal(t, types.TriggerClock, exec.TriggerType)
|
|
assert.Equal(t, types.ExecCompleted, exec.Status)
|
|
})
|
|
|
|
t.Run("ListExecutions filters by member", func(t *testing.T) {
|
|
result, err := api.ListExecutions(ctx, "member_api_exec", &api.ExecutionQuery{
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should have 3 executions for member_api_exec
|
|
assert.Equal(t, 3, result.Total)
|
|
assert.Len(t, result.Data, 3)
|
|
|
|
// Verify all returned executions are for the correct member
|
|
for _, exec := range result.Data {
|
|
assert.Equal(t, "member_api_exec", exec.MemberID)
|
|
}
|
|
})
|
|
|
|
t.Run("ListExecutions filters by status", func(t *testing.T) {
|
|
result, err := api.ListExecutions(ctx, "member_api_exec", &api.ExecutionQuery{
|
|
Status: types.ExecCompleted,
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should have only completed executions
|
|
assert.Equal(t, 1, result.Total)
|
|
for _, exec := range result.Data {
|
|
assert.Equal(t, types.ExecCompleted, exec.Status)
|
|
}
|
|
})
|
|
|
|
t.Run("ListExecutions filters by trigger type", func(t *testing.T) {
|
|
result, err := api.ListExecutions(ctx, "member_api_exec", &api.ExecutionQuery{
|
|
Trigger: types.TriggerClock,
|
|
Page: 1,
|
|
PageSize: 10,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should have only clock trigger executions
|
|
assert.Equal(t, 2, result.Total)
|
|
for _, exec := range result.Data {
|
|
assert.Equal(t, types.TriggerClock, exec.TriggerType)
|
|
}
|
|
})
|
|
|
|
t.Run("ListExecutions pagination works", func(t *testing.T) {
|
|
// Page 1 with size 2
|
|
result1, err := api.ListExecutions(ctx, "member_api_exec", &api.ExecutionQuery{
|
|
Page: 1,
|
|
PageSize: 2,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.GreaterOrEqual(t, len(result1.Data), 2, "Should have at least 2 executions on page 1")
|
|
|
|
// Page 2 with size 2
|
|
result2, err := api.ListExecutions(ctx, "member_api_exec", &api.ExecutionQuery{
|
|
Page: 2,
|
|
PageSize: 2,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.GreaterOrEqual(t, len(result2.Data), 1, "Should have at least 1 execution on page 2")
|
|
})
|
|
}
|
|
|
|
// TestAPITriggerWithData tests trigger APIs with real robots
|
|
func TestAPITriggerWithData(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 test robot
|
|
setupAPITestRobot(t, "robot_api_trigger_001", "team_api_trigger")
|
|
|
|
// Start manager
|
|
err := api.Start()
|
|
require.NoError(t, err)
|
|
defer api.Stop()
|
|
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
t.Run("TriggerManual accepts valid robot", func(t *testing.T) {
|
|
result, err := api.TriggerManual(ctx, "robot_api_trigger_001", types.TriggerClock, nil)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
assert.True(t, result.Accepted)
|
|
assert.NotEmpty(t, result.JobID)
|
|
assert.Contains(t, result.Message, "submitted")
|
|
})
|
|
|
|
t.Run("Trigger with human type", func(t *testing.T) {
|
|
result, err := api.Trigger(ctx, "robot_api_trigger_001", &api.TriggerRequest{
|
|
Type: types.TriggerHuman,
|
|
Action: types.ActionTaskAdd,
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Result should be returned (accepted or not depends on robot state)
|
|
// The important thing is that the API doesn't error
|
|
t.Logf("Trigger result: accepted=%v, message=%s", result.Accepted, result.Message)
|
|
})
|
|
|
|
t.Run("Trigger with event type", func(t *testing.T) {
|
|
result, err := api.Trigger(ctx, "robot_api_trigger_001", &api.TriggerRequest{
|
|
Type: types.TriggerEvent,
|
|
Source: types.EventWebhook,
|
|
EventType: "test.event",
|
|
Data: map[string]interface{}{"key": "value"},
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, result)
|
|
|
|
// Should be accepted (robot exists and has event enabled)
|
|
assert.True(t, result.Accepted)
|
|
})
|
|
|
|
t.Run("Trigger rejects non-existent robot", func(t *testing.T) {
|
|
result, err := api.Trigger(ctx, "robot_api_nonexistent", &api.TriggerRequest{
|
|
Type: types.TriggerHuman,
|
|
})
|
|
// Should not return error, but result should show not accepted
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.False(t, result.Accepted)
|
|
})
|
|
}
|
|
|
|
// ==================== 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
|
|
func setupAPITestRobot(t *testing.T, memberID, teamID string) {
|
|
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,
|
|
},
|
|
"triggers": map[string]interface{}{
|
|
"clock": map[string]interface{}{"enabled": true},
|
|
"intervene": map[string]interface{}{"enabled": true},
|
|
"event": map[string]interface{}{"enabled": true},
|
|
},
|
|
"clock": map[string]interface{}{
|
|
"mode": "interval",
|
|
"every": "1h",
|
|
"timeout": "30m",
|
|
},
|
|
}
|
|
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": true,
|
|
"robot_status": "idle",
|
|
"robot_config": string(configJSON),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert robot %s: %v", memberID, err)
|
|
}
|
|
}
|
|
|
|
// setupAPITestExecution creates a test execution in the database
|
|
func setupAPITestExecution(t *testing.T, execID, memberID string, triggerType types.TriggerType, status types.ExecStatus) {
|
|
s := store.NewExecutionStore()
|
|
ctx := context.Background()
|
|
|
|
startTime := time.Now().Add(-1 * time.Hour)
|
|
record := &store.ExecutionRecord{
|
|
ExecutionID: execID,
|
|
MemberID: memberID,
|
|
TeamID: "team_api_exec",
|
|
JobID: "job_" + execID,
|
|
TriggerType: triggerType,
|
|
Status: status,
|
|
Phase: types.PhaseDelivery,
|
|
StartTime: &startTime,
|
|
}
|
|
|
|
if status == types.ExecCompleted || status == types.ExecFailed {
|
|
endTime := time.Now()
|
|
record.EndTime = &endTime
|
|
}
|
|
|
|
err := s.Save(ctx, record)
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert execution %s: %v", execID, err)
|
|
}
|
|
}
|
|
|
|
// cleanupAPITestRobots removes all API test robots
|
|
func cleanupAPITestRobots(t *testing.T) {
|
|
m := model.Select("__yao.member")
|
|
if m == nil {
|
|
return
|
|
}
|
|
tableName := m.MetaData.Table.Name
|
|
qb := capsule.Query()
|
|
|
|
// Delete all robots with member_id starting with "robot_api_" or "api_robot_"
|
|
_, err := qb.Table(tableName).Where("member_id", "like", "robot_api_%").Delete()
|
|
if err != nil {
|
|
t.Logf("Warning: cleanup robots error: %v", err)
|
|
}
|
|
|
|
// Also delete "api_robot_" prefixed robots (new tests)
|
|
_, err = qb.Table(tableName).Where("member_id", "like", "api_robot_%").Delete()
|
|
if err != nil {
|
|
t.Logf("Warning: cleanup robots error: %v", err)
|
|
}
|
|
}
|
|
|
|
// cleanupAPITestExecutions removes all API test executions
|
|
func cleanupAPITestExecutions(t *testing.T) {
|
|
m := model.Select("__yao.agent.execution")
|
|
if m == nil {
|
|
t.Logf("Warning: model __yao.agent.execution not found, skipping cleanup")
|
|
return
|
|
}
|
|
tableName := m.MetaData.Table.Name
|
|
qb := capsule.Query()
|
|
|
|
// Delete all executions with execution_id starting with "exec_api_"
|
|
_, err := qb.Table(tableName).Where("execution_id", "like", "exec_api_%").Delete()
|
|
if err != nil {
|
|
t.Logf("Warning: cleanup executions error: %v", err)
|
|
}
|
|
|
|
// Also delete executions for API test members
|
|
_, err = qb.Table(tableName).Where("member_id", "like", "member_api_%").Delete()
|
|
if err != nil {
|
|
t.Logf("Warning: cleanup executions error: %v", err)
|
|
}
|
|
}
|