package rpc import ( "context" "errors" "path/filepath" "strings" "testing" "time" agentpb "git.ipao.vip/rogee/go-sip/gen/agent" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" ) func authorizedMockRequest(now time.Time) *agentpb.ExecuteAuthorizedRequest { return &agentpb.ExecuteAuthorizedRequest{ SchemaVersion: "agent-authorized-origination.v0.1", Meta: testMeta("authorized-1", "authorized-key-1", 1), Binding: &agentpb.ExecutionBinding{ TenantId: "tenant-1", TenantKey: "tenant-original", ExecutionId: "execution-authorized-1", TaskId: "task-1", TaskItemId: "command-1", TaskRevision: 2, AgentVersionId: "agent-version-1", RoutePolicyId: "route-1", CallerProfileId: "caller-1", }, SelectedTrunkId: "trunk-1", CallerId: "BD93205882", Callee: "15003164745", RingTimeoutMs: 12000, MaxCallDurationMs: 30000, DialBeforeUnixMs: now.Add(time.Minute).UnixMilli(), BoundSnapshotSha256: strings.Repeat("a", 64), } } func TestExecuteAuthorizedMockOneShotAndIdentity(t *testing.T) { now := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC) attempts := 0 server := NewServer(ServerOptions{Mode: "mock", Now: func() time.Time { return now }, MockAuthorizedOriginate: func(_ context.Context, req *agentpb.ExecuteAuthorizedRequest) error { attempts++ if req.SelectedTrunkId != "trunk-1" || req.CallerId != "BD93205882" || req.MaxCallDurationMs != 30000 { t.Fatalf("Agent received modified Dispatcher decision: %+v", req) } return nil }}) activateTestServer(t, server) req := authorizedMockRequest(now) first, err := server.ExecuteAuthorized(context.Background(), req) if err != nil || first.GetReceipt().GetResult() != agentpb.ResultCode_RESULT_CODE_APPLIED || first.GetState() != agentpb.ExecutionState_EXECUTION_STATE_TERMINAL || attempts != 1 { t.Fatalf("first mock execution=%+v attempts=%d err=%v", first, attempts, err) } replay, err := server.ExecuteAuthorized(context.Background(), req) if err != nil || replay.GetReceipt().GetMeta().GetOperationId() != first.GetReceipt().GetMeta().GetOperationId() || attempts != 1 { t.Fatalf("replay caused duplicate mock dial: %+v attempts=%d err=%v", replay, attempts, err) } changed := proto.Clone(req).(*agentpb.ExecuteAuthorizedRequest) changed.Callee = "15830461047" conflict, err := server.ExecuteAuthorized(context.Background(), changed) if err != nil || conflict.GetReceipt().GetResult() != agentpb.ResultCode_RESULT_CODE_CONFLICT || attempts != 1 { t.Fatalf("same key/different body: %+v attempts=%d err=%v", conflict, attempts, err) } newKey := proto.Clone(req).(*agentpb.ExecuteAuthorizedRequest) newKey.Meta = testMeta("authorized-2", "authorized-key-2", 1) conflict, err = server.ExecuteAuthorized(context.Background(), newKey) if err != nil || conflict.GetReceipt().GetResult() != agentpb.ResultCode_RESULT_CODE_CONFLICT || attempts != 1 { t.Fatalf("same execution/new operation: %+v attempts=%d err=%v", conflict, attempts, err) } } func TestExecuteAuthorizedRejectsExpiredAndInvalidMock(t *testing.T) { now := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC) attempts := 0 server := NewServer(ServerOptions{Mode: "mock", Now: func() time.Time { return now }, MockAuthorizedOriginate: func(context.Context, *agentpb.ExecuteAuthorizedRequest) error { attempts++ return nil }}) activateTestServer(t, server) for _, tc := range []struct { name string change func(*agentpb.ExecuteAuthorizedRequest) }{ {"expired at Agent", func(r *agentpb.ExecuteAuthorizedRequest) { r.DialBeforeUnixMs = now.UnixMilli() }}, {"missing selected trunk", func(r *agentpb.ExecuteAuthorizedRequest) { r.SelectedTrunkId = "" }}, {"invalid snapshot digest", func(r *agentpb.ExecuteAuthorizedRequest) { r.BoundSnapshotSha256 = "bad" }}, {"unknown contract version", func(r *agentpb.ExecuteAuthorizedRequest) { r.SchemaVersion = "other" }}, } { t.Run(tc.name, func(t *testing.T) { req := authorizedMockRequest(now) tc.change(req) response, err := server.ExecuteAuthorized(context.Background(), req) if response != nil || status.Code(err) != codes.InvalidArgument && status.Code(err) != codes.FailedPrecondition { t.Fatalf("invalid decision response=%+v err=%v", response, err) } if attempts != 0 { t.Fatalf("invalid decision reached mock dial %d times", attempts) } }) } } func TestExecuteAuthorizedMockFailureIsUnknownAndNeverRetried(t *testing.T) { now := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC) attempts := 0 server := NewServer(ServerOptions{Mode: "mock", Now: func() time.Time { return now }, MockAuthorizedOriginate: func(context.Context, *agentpb.ExecuteAuthorizedRequest) error { attempts++ return errors.New("mock transport failed") }}) activateTestServer(t, server) req := authorizedMockRequest(now) first, err := server.ExecuteAuthorized(context.Background(), req) if err != nil || first.GetReceipt().GetResult() != agentpb.ResultCode_RESULT_CODE_UNKNOWN || attempts != 1 { t.Fatalf("uncertain mock execution=%+v attempts=%d err=%v", first, attempts, err) } replay, err := server.ExecuteAuthorized(context.Background(), req) if err != nil || replay.GetReceipt().GetResult() != agentpb.ResultCode_RESULT_CODE_UNKNOWN || attempts != 1 { t.Fatalf("uncertain execution redialed: %+v attempts=%d err=%v", replay, attempts, err) } } func TestExecuteAuthorizedJournalPreventsRedialAfterAgentRestart(t *testing.T) { for _, tc := range []struct { name string fail bool }{ {"mock completed", false}, {"mock outcome unknown", true}, } { t.Run(tc.name, func(t *testing.T) { now := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC) path := filepath.Join(t.TempDir(), "agent-session.json") attempts := 0 start := func(generation uint64, bootID string) *Server { server := NewServer(ServerOptions{Mode: "mock", Now: func() time.Time { return now }, StatePath: path, Status: &agentpb.AgentStatus{AgentId: "agent-1", CellId: "cell-1", BootId: bootID}, MockAuthorizedOriginate: func(context.Context, *agentpb.ExecuteAuthorizedRequest) error { attempts++ if tc.fail { return errors.New("mock adapter failed") } return nil }, }) meta := testMeta("activate", "", 0) meta.BootId = bootID if _, err := server.ActivateAgent(context.Background(), &agentpb.ActivateAgentRequest{ Meta: meta, Binding: &agentpb.AgentBinding{AgentId: "agent-1", CellId: "cell-1", ExpectedBootId: bootID, DispatcherEpoch: "epoch-1", SessionGeneration: generation}, ActivationOperationId: "activate", }); err != nil { t.Fatal(err) } return server } first := start(1, "boot-1") req := authorizedMockRequest(now) response, err := first.ExecuteAuthorized(context.Background(), req) if err != nil || response == nil || attempts != 1 { t.Fatalf("first mock call: response=%+v attempts=%d err=%v", response, attempts, err) } terminalObservedAt := now.UnixMilli() now = now.Add(time.Hour) recovered := start(2, "boot-2") replay := proto.Clone(req).(*agentpb.ExecuteAuthorizedRequest) replay.Meta = testMeta("authorized-new-boot", "authorized-key-new-boot", 2) replay.Meta.BootId = "boot-2" retry, err := recovered.ExecuteAuthorized(context.Background(), replay) if err != nil || retry.GetReceipt().GetResult() == agentpb.ResultCode_RESULT_CODE_APPLIED || attempts != 1 { t.Fatalf("restart redialed execution: response=%+v attempts=%d err=%v", retry, attempts, err) } queryMeta := testMeta("query-recovered", "query-recovered-key", 2) queryMeta.BootId = "boot-2" query, err := recovered.QueryExecution(context.Background(), &agentpb.QueryExecutionRequest{Meta: queryMeta, Binding: req.Binding}) if err != nil || query.Snapshot == nil || query.Snapshot.Unknown != tc.fail { t.Fatalf("recovered state failed to retain uncertainty: %+v err=%v", query, err) } if !tc.fail && query.Snapshot.ObservedAtUnixMs != terminalObservedAt { t.Fatalf("terminal observation drifted after restart: got=%d want=%d", query.Snapshot.ObservedAtUnixMs, terminalObservedAt) } }) } } func TestExecuteAuthorizedCannotDialOutsideMockOrWithoutAdapter(t *testing.T) { now := time.Date(2026, 9, 21, 1, 30, 0, 0, time.UTC) for _, tc := range []struct { name string mode string }{ {"mixed disabled", "mixed"}, {"real disabled", "real"}, {"mock adapter missing", "mock"}, } { t.Run(tc.name, func(t *testing.T) { server := NewServer(ServerOptions{Mode: tc.mode, Now: func() time.Time { return now }}) activateTestServer(t, server) response, err := server.ExecuteAuthorized(context.Background(), authorizedMockRequest(now)) if response != nil || status.Code(err) != codes.FailedPrecondition { t.Fatalf("unavailable mode/adapter response=%+v err=%v", response, err) } }) } }