- Introduced multiple executor modes (Standard, DryRun, Sandbox) to accommodate various use cases, enhancing flexibility in execution strategies. - Updated DESIGN.md to reflect the new executor modes and their respective use cases, including detailed descriptions and configuration examples. - Revised TECHNICAL.md to outline the new executor package structure, emphasizing the modular design for future enhancements. - Enhanced the TODO.md to track the progress of executor mode implementations and related tasks. - Removed outdated executor stub files and tests, streamlining the codebase for improved maintainability. - Updated integration tests to utilize the new DryRun executor, ensuring comprehensive coverage of execution scenarios without real agent calls.
126 lines
3.8 KiB
Go
126 lines
3.8 KiB
Go
package executor
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/yaoapp/yao/agent/robot/types"
|
|
)
|
|
|
|
// Smoke tests to verify basic flow works
|
|
// These tests use SkipJobIntegration=true to avoid DB dependencies
|
|
// Real integration tests are in manager_test.go and job_test.go
|
|
|
|
func TestExecutorSmoke(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
robot := &types.Robot{
|
|
MemberID: "test-smoke",
|
|
TeamID: "team-1",
|
|
Config: &types.Config{Quota: &types.Quota{Max: 1}},
|
|
}
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
result, err := exec.Execute(ctx, robot, types.TriggerClock, nil)
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, types.ExecCompleted, result.Status)
|
|
assert.Equal(t, types.TriggerClock, result.TriggerType)
|
|
|
|
// Clock trigger executes all phases (P0-P5)
|
|
assert.NotNil(t, result.Inspiration, "P0 should be executed for clock trigger")
|
|
assert.NotNil(t, result.Goals, "P1 should be executed")
|
|
assert.NotEmpty(t, result.Tasks, "P2 should generate tasks")
|
|
assert.NotEmpty(t, result.Results, "P3 should generate results")
|
|
assert.NotNil(t, result.Delivery, "P4 should be executed")
|
|
assert.NotEmpty(t, result.Learning, "P5 should be executed")
|
|
}
|
|
|
|
func TestExecutorHumanTriggerSkipsP0(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
robot := &types.Robot{
|
|
MemberID: "test-human",
|
|
TeamID: "team-1",
|
|
Config: &types.Config{Quota: &types.Quota{Max: 1}},
|
|
}
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
result, err := exec.Execute(ctx, robot, types.TriggerHuman, nil)
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, types.ExecCompleted, result.Status)
|
|
|
|
// Human trigger skips P0 (Inspiration)
|
|
assert.Nil(t, result.Inspiration, "P0 should be skipped for human trigger")
|
|
assert.NotNil(t, result.Goals, "P1 should be executed")
|
|
}
|
|
|
|
func TestExecutorEventTriggerSkipsP0(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
robot := &types.Robot{
|
|
MemberID: "test-event",
|
|
TeamID: "team-1",
|
|
Config: &types.Config{Quota: &types.Quota{Max: 1}},
|
|
}
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
result, err := exec.Execute(ctx, robot, types.TriggerEvent, nil)
|
|
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, result.Inspiration, "P0 should be skipped for event trigger")
|
|
assert.NotNil(t, result.Goals)
|
|
}
|
|
|
|
func TestExecutorNilRobot(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
result, err := exec.Execute(ctx, nil, types.TriggerClock, nil)
|
|
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
assert.Contains(t, err.Error(), "robot cannot be nil")
|
|
}
|
|
|
|
func TestExecutorSimulatedFailure(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
robot := &types.Robot{
|
|
MemberID: "test-fail",
|
|
TeamID: "team-1",
|
|
Config: &types.Config{Quota: &types.Quota{Max: 1}},
|
|
}
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
// Pass "simulate_failure" to trigger simulated failure
|
|
result, err := exec.Execute(ctx, robot, types.TriggerClock, "simulate_failure")
|
|
|
|
assert.NoError(t, err) // Execute returns nil error, failure is in result
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, types.ExecFailed, result.Status)
|
|
assert.Equal(t, "simulated failure", result.Error)
|
|
}
|
|
|
|
func TestExecutorCounters(t *testing.T) {
|
|
exec := NewDryRunWithDelay(0)
|
|
robot := &types.Robot{
|
|
MemberID: "test-counter",
|
|
TeamID: "team-1",
|
|
Config: &types.Config{Quota: &types.Quota{Max: 10}},
|
|
}
|
|
ctx := types.NewContext(context.Background(), nil)
|
|
|
|
assert.Equal(t, 0, exec.ExecCount())
|
|
assert.Equal(t, 0, exec.CurrentCount())
|
|
|
|
_, _ = exec.Execute(ctx, robot, types.TriggerClock, nil)
|
|
assert.Equal(t, 1, exec.ExecCount())
|
|
assert.Equal(t, 0, exec.CurrentCount()) // Completed, so 0
|
|
|
|
_, _ = exec.Execute(ctx, robot, types.TriggerClock, nil)
|
|
assert.Equal(t, 2, exec.ExecCount())
|
|
|
|
exec.Reset()
|
|
assert.Equal(t, 0, exec.ExecCount())
|
|
}
|