Files
go-sip/internal/rpc/approved_integration_test.go
T

89 lines
3.2 KiB
Go

package rpc
import (
"context"
"encoding/json"
"net"
"os"
"path/filepath"
"testing"
"time"
agentpb "git.ipao.vip/rogee/go-sip/gen/agent"
"git.ipao.vip/rogee/go-sip/internal/configread"
"git.ipao.vip/rogee/go-sip/internal/dispatcher"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
)
func mockApprovedGRPC(t *testing.T, server *Server) agentpb.AgentControlServiceClient {
t.Helper()
listener := bufconn.Listen(1 << 20)
grpcServer := grpc.NewServer()
agentpb.RegisterAgentControlServiceServer(grpcServer, server)
go func() { _ = grpcServer.Serve(listener) }()
t.Cleanup(grpcServer.Stop)
t.Cleanup(func() { _ = listener.Close() })
conn, err := grpc.NewClient("bufnet",
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return listener.Dial() }),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = conn.Close() })
return agentpb.NewAgentControlServiceClient(conn)
}
func TestApprovedDispatcherToAgentUnaryMockRetainsSnapshotAndOneShotCall(t *testing.T) {
now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC)
req := approvedTestRequest(t, now)
calls := 0
agent := activatedApprovedServer(t, now, filepath.Join(t.TempDir(), "agent-session.json"), req.DispatcherId, 1,
func(_ context.Context, call ApprovedExecution) error {
calls++
if call.SIPRevision != 8 || call.AI.Mode != "asr_only" || call.AI.ASR.Provider.Credential != "example-only-not-a-real-secret" || call.MaxCallDuration != 20*time.Second {
t.Fatal("Agent received the wrong frozen execution configuration")
}
return nil
})
client := mockApprovedGRPC(t, agent)
orig := &dispatcher.ApprovedOriginator{DispatcherID: req.DispatcherId, Client: client,
Meta: func(context.Context) (*agentpb.RequestMeta, error) { return testMeta("inspect-loaded", "", 1), nil },
}
sipJSON, err := os.ReadFile("../../contracts/local/examples/config-read-sip.json")
if err != nil {
t.Fatal(err)
}
var sip configread.CurrentSIP
if err := json.Unmarshal(sipJSON, &sip); err != nil {
t.Fatal(err)
}
var task configread.CurrentTask
if err := json.Unmarshal(req.TaskConfigJson, &task); err != nil {
t.Fatal(err)
}
var providers map[string]configread.CurrentProvider
if err := json.Unmarshal(req.ProvidersJson, &providers); err != nil {
t.Fatal(err)
}
snapshot := configread.CurrentSnapshot{SIP: sip, Task: task, Providers: providers}
if err := orig.VerifySIP(context.Background(), sip); err != nil {
t.Fatal(err)
}
spec := dispatcher.CurrentCallSpec{
EventID: req.SourceEventId, TaskID: task.TaskID, TenantID: task.TenantID,
TrunkID: req.SelectedTrunkId, Callee: req.Callee, DialedCallee: req.DialedCallee,
CallerID: req.CallerId, RingTimeoutMS: req.RingTimeoutMs,
MaxCallDurationMS: req.MaxCallDurationMs, Deadline: time.UnixMilli(req.DialBeforeUnixMs),
Snapshot: snapshot,
}
if err := orig.Originate(context.Background(), spec); err != nil || calls != 1 {
t.Fatalf("approved mock call was not accepted once: calls=%d err=%v", calls, err)
}
if err := orig.Originate(context.Background(), spec); err == nil || calls != 1 {
t.Fatalf("duplicate unary call must not redial: calls=%d err=%v", calls, err)
}
}