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

101 lines
4.4 KiB
Go

package rpc
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
agentpb "git.ipao.vip/rogee/go-sip/gen/agent"
"git.ipao.vip/rogee/go-sip/internal/calllog"
"git.ipao.vip/rogee/go-sip/internal/contract"
"git.ipao.vip/rogee/go-sip/internal/testfixture"
)
func TestServerWritesPhoneCorrelatedCallBusinessLog(t *testing.T) {
now := time.Date(2026, 9, 18, 1, 0, 0, 0, time.UTC)
logger, err := calllog.New(filepath.Join(t.TempDir(), "business", "calls.jsonl"), []byte("0123456789abcdef"), func() time.Time { return now })
if err != nil {
t.Fatal(err)
}
server := NewServer(ServerOptions{Now: func() time.Time { return now }, CallLogger: logger})
meta := testMeta("activate-log", "", 0)
if _, err := server.ActivateAgent(context.Background(), &agentpb.ActivateAgentRequest{
Meta: meta,
Binding: &agentpb.AgentBinding{AgentId: "agent-1", CellId: "cell-1", ExpectedBootId: "boot-1", DispatcherEpoch: "epoch-1", SessionGeneration: 1},
ActivationOperationId: "activate-log",
}); err != nil {
t.Fatal(err)
}
raw, err := testfixture.Execute()
if err != nil {
t.Fatal(err)
}
envelope, payload, err := contract.DecodeExecute(raw)
if err != nil {
t.Fatal(err)
}
binding := &agentpb.ExecutionBinding{
TenantId: envelope.TenantID, TenantKey: envelope.TenantKey, ExecutionId: payload.ExecutionID,
TaskId: payload.TaskID, TaskItemId: payload.TaskItemID, TaskRevision: payload.TaskRevision,
AgentVersionId: payload.AgentVersionID, RoutePolicyId: payload.RoutePolicyID, CallerProfileId: payload.CallerProfileID,
}
if _, err := server.Execute(context.Background(), &agentpb.ExecuteRequest{
Meta: testMeta("execute-log", "execute-log-key", 1), Binding: binding, CallExecuteJson: raw,
ConfigSha256: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}); err != nil {
t.Fatal(err)
}
statusPayload := []byte(`{"call_id":"call-1","execution_id":"execution-1","call_state":"answered","attempt_id":"attempt-1","attempt_state":"active","route_policy_id":"route-sip-first","caller_profile_id":"caller-sip-first","trunk_id":"provider-primary","cell_id":"cell-1","sip_stage":"invite","sip_status_code":183}`)
if _, err := server.ReportExecutionEvent(context.Background(), &agentpb.ReportExecutionEventRequest{
Meta: testMeta("fact-status", "fact-status-key", 1), Fact: &agentpb.ExecutionFact{
FactId: "fact-status", ContentSha256: "digest-status", Binding: binding,
Kind: agentpb.FactKind_FACT_KIND_CALL_STATUS, PayloadJson: statusPayload,
},
}); err != nil {
t.Fatal(err)
}
finishedPayload := []byte(`{"call_id":"call-1","execution_id":"execution-1","outcome":"no_answer","duration_ms":3000,"reason_code":"provider_480","asset_state":"failed","attempt_summary":[{"attempt_id":"attempt-1","state":"ended","trunk_id":"provider-primary","cell_id":"cell-1","reason_code":"provider_480"}],"recording_id":"recording-1","recording_state":"failed"}`)
if _, err := server.ReportExecutionEvent(context.Background(), &agentpb.ReportExecutionEventRequest{
Meta: testMeta("fact-finished", "fact-finished-key", 1), Fact: &agentpb.ExecutionFact{
FactId: "fact-finished", ContentSha256: "digest-finished", Binding: binding,
Kind: agentpb.FactKind_FACT_KIND_CALL_FINISHED, PayloadJson: finishedPayload,
},
}); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(logger.Path())
if err != nil {
t.Fatal(err)
}
text := string(data)
if strings.Contains(text, payload.Callee) {
t.Fatalf("business log contains original phone: %s", text)
}
lines := strings.Split(strings.TrimSpace(text), "\n")
if len(lines) != 4 {
t.Fatalf("got %d business log lines, want prepared/status/finished/attempt: %s", len(lines), text)
}
var records []map[string]any
for _, line := range lines {
var record map[string]any
if err := json.Unmarshal([]byte(line), &record); err != nil {
t.Fatal(err)
}
records = append(records, record)
}
if records[0]["event_type"] != "execution.prepared" || records[1]["sip_status_code"] != float64(183) {
t.Fatalf("prepared or SIP status record missing: %#v", records)
}
if records[2]["recording_id"] != "recording-1" || records[2]["result"] != "no_answer" || records[3]["trunk_id"] != "provider-primary" {
t.Fatalf("finished or attempt record missing: %#v", records)
}
if records[0]["phone_ref"] != records[1]["phone_ref"] || records[1]["phone_ref"] != records[2]["phone_ref"] {
t.Fatalf("phone correlation changed across events: %#v", records)
}
}