Add configurable external rules pipeline for ingress #19
@@ -196,6 +196,11 @@ func (d *Dispatcher) buildHistory(threadID string) ([]historyEntry, error) {
|
||||
return history, nil
|
||||
}
|
||||
|
||||
// ExportBuildDispatchMetadata exports buildDispatchMetadata for testing.
|
||||
func ExportBuildDispatchMetadata(task *database.Task) map[string]string {
|
||||
return buildDispatchMetadata(task)
|
||||
}
|
||||
|
||||
// buildDispatchMetadata constructs the metadata map for OpenClaw dispatch,
|
||||
// merging the task UUID with any DispatchContext from the rules pipeline.
|
||||
func buildDispatchMetadata(task *database.Task) map[string]string {
|
||||
|
||||
@@ -12,6 +12,53 @@ import (
|
||||
"thuanle.me/claw-email-bridge/internal/database"
|
||||
)
|
||||
|
||||
func TestBuildDispatchMetadata_ForwardsContext(t *testing.T) {
|
||||
task := &database.Task{
|
||||
TaskUUID: "uuid-ctx-test",
|
||||
DispatchContext: `{"rule":"whitelist","source":"env"}`,
|
||||
}
|
||||
metadata := ai_client.ExportBuildDispatchMetadata(task)
|
||||
|
||||
if metadata["task_uuid"] != "uuid-ctx-test" {
|
||||
t.Errorf("expected task_uuid=uuid-ctx-test, got %q", metadata["task_uuid"])
|
||||
}
|
||||
if metadata["rule"] != "whitelist" {
|
||||
t.Errorf("expected rule=whitelist, got %q", metadata["rule"])
|
||||
}
|
||||
if metadata["source"] != "env" {
|
||||
t.Errorf("expected source=env, got %q", metadata["source"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDispatchMetadata_ProtectsTaskUUID(t *testing.T) {
|
||||
task := &database.Task{
|
||||
TaskUUID: "original-uuid",
|
||||
DispatchContext: `{"task_uuid":"malicious-override","extra":"data"}`,
|
||||
}
|
||||
metadata := ai_client.ExportBuildDispatchMetadata(task)
|
||||
|
||||
if metadata["task_uuid"] != "original-uuid" {
|
||||
t.Errorf("task_uuid should not be overwritten, got %q", metadata["task_uuid"])
|
||||
}
|
||||
if metadata["extra"] != "data" {
|
||||
t.Errorf("expected extra=data, got %q", metadata["extra"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDispatchMetadata_NoContext(t *testing.T) {
|
||||
task := &database.Task{
|
||||
TaskUUID: "uuid-no-ctx",
|
||||
}
|
||||
metadata := ai_client.ExportBuildDispatchMetadata(task)
|
||||
|
||||
if len(metadata) != 1 {
|
||||
t.Errorf("expected 1 key, got %d", len(metadata))
|
||||
}
|
||||
if metadata["task_uuid"] != "uuid-no-ctx" {
|
||||
t.Errorf("expected task_uuid=uuid-no-ctx, got %q", metadata["task_uuid"])
|
||||
}
|
||||
}
|
||||
|
||||
// Test matrix #2: OpenClaw fail 2 lần, lần 3 thành công → COMPLETED, attempt_openclaw = 3.
|
||||
func TestDispatch_RetryThenSuccess(t *testing.T) {
|
||||
tdb := database.NewTestDB(t)
|
||||
|
||||
@@ -47,6 +47,7 @@ Bảng `tasks`:
|
||||
- `status` TEXT
|
||||
- `attempt_openclaw` INTEGER DEFAULT 0
|
||||
- `attempt_smtp` INTEGER DEFAULT 0
|
||||
- `dispatch_context` TEXT (JSON metadata từ external rules pipeline, truyền qua OpenClaw dispatch)
|
||||
- `last_error` TEXT NULL
|
||||
- `next_retry_at` DATETIME NULL (chỉ cần nếu retry xử lý theo scheduler/worker)
|
||||
- `created_at` DATETIME
|
||||
|
||||
Reference in New Issue
Block a user