87 lines
3.8 KiB
Go
87 lines
3.8 KiB
Go
package dispatcher
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
agentpb "git.ipao.vip/rogee/go-sip/gen/agent"
|
|
"github.com/google/uuid"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
func TestApprovedAgentControlUsesTaskIdentityAndNoExternalCommandDedup(t *testing.T) {
|
|
fake := &fakeApprovedAgentRPC{}
|
|
originator, execution := approvedOriginatorFixture(t, fake)
|
|
var lastOperation string
|
|
for _, tc := range []struct {
|
|
action, policy string
|
|
wantAction agentpb.ControlAction
|
|
wantPolicy agentpb.ActiveCallPolicy
|
|
}{
|
|
{"pause", "hangup", agentpb.ControlAction_CONTROL_ACTION_PAUSE, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_HANGUP},
|
|
{"stop", "drain", agentpb.ControlAction_CONTROL_ACTION_STOP, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_DRAIN},
|
|
{"resume", "", agentpb.ControlAction_CONTROL_ACTION_RESUME, agentpb.ActiveCallPolicy_ACTIVE_CALL_POLICY_UNSPECIFIED},
|
|
} {
|
|
spec := ControlSpec{DispatcherID: originator.DispatcherID, TenantID: execution.TenantID, TaskID: execution.TaskID, Action: tc.action, ActiveCallPolicy: tc.policy, Reason: "synthetic-private-reason-not-for-agent"}
|
|
if err := originator.SendControl(context.Background(), spec); err != nil {
|
|
t.Fatalf("current %s control was not applied: %v", tc.action, err)
|
|
}
|
|
req := fake.controlRequest
|
|
if req == nil || req.DispatcherId != spec.DispatcherID || req.TenantId != spec.TenantID || req.TaskId != spec.TaskID || req.Action != tc.wantAction || req.ActiveCallPolicy != tc.wantPolicy {
|
|
t.Fatal("Agent received a different task-level control")
|
|
}
|
|
if req.Meta == nil || req.Meta.IdempotencyKey != "" || uuid.Validate(req.Meta.OperationId) != nil || req.Meta.OperationId == lastOperation {
|
|
t.Fatal("control reused an external command ID, idempotency key or RPC trace")
|
|
}
|
|
if strings.Contains(req.String(), spec.Reason) {
|
|
t.Fatal("control leaked the SaaS reason into the Agent request")
|
|
}
|
|
lastOperation = req.Meta.OperationId
|
|
}
|
|
if fake.controlCalls != 3 {
|
|
t.Fatalf("controls were silently deduplicated: %d", fake.controlCalls)
|
|
}
|
|
}
|
|
|
|
func TestApprovedAgentControlRejectsInvalidInstructionsAndUnknownReply(t *testing.T) {
|
|
fake := &fakeApprovedAgentRPC{}
|
|
originator, execution := approvedOriginatorFixture(t, fake)
|
|
base := ControlSpec{DispatcherID: originator.DispatcherID, TenantID: execution.TenantID, TaskID: execution.TaskID, Action: "pause", ActiveCallPolicy: "hangup"}
|
|
for _, tc := range []struct {
|
|
name string
|
|
edit func(*ControlSpec)
|
|
}{
|
|
{"wrong dispatcher", func(spec *ControlSpec) { spec.DispatcherID = "another-dispatcher" }},
|
|
{"tenant zero", func(spec *ControlSpec) { spec.TenantID = 0 }},
|
|
{"task missing", func(spec *ControlSpec) { spec.TaskID = "" }},
|
|
{"unsupported action", func(spec *ControlSpec) { spec.Action = "restart" }},
|
|
{"pause missing policy", func(spec *ControlSpec) { spec.ActiveCallPolicy = "" }},
|
|
{"resume with hangup", func(spec *ControlSpec) { spec.Action = "resume" }},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
spec := base
|
|
tc.edit(&spec)
|
|
if err := originator.SendControl(context.Background(), spec); err == nil {
|
|
t.Fatal("invalid Agent control was dispatched")
|
|
}
|
|
if fake.controlCalls != 0 {
|
|
t.Fatal("invalid Agent control reached RPC")
|
|
}
|
|
})
|
|
}
|
|
fake.controlResponse = &agentpb.ApplyApprovedTaskControlResponse{}
|
|
if err := originator.SendControl(context.Background(), base); err == nil {
|
|
t.Fatal("unapplied Agent response was treated as completed")
|
|
}
|
|
fake.controlResponse = nil
|
|
fake.controlErr = status.Error(codes.DeadlineExceeded, "synthetic unknown outcome")
|
|
if err := originator.SendControl(context.Background(), base); status.Code(err) != codes.DeadlineExceeded {
|
|
t.Fatalf("unknown Agent outcome was suppressed: %v", err)
|
|
}
|
|
if fake.controlCalls != 2 {
|
|
t.Fatalf("Agent RPC was retried or silently skipped: %d", fake.controlCalls)
|
|
}
|
|
}
|