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

74 lines
3.3 KiB
Go

package rpc
import (
"bytes"
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
"git.ipao.vip/rogee/go-sip/internal/configread"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestApprovedAgentReceivesFrozenASROnlySnapshot(t *testing.T) {
now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC)
req := approvedTestRequest(t, now)
req.TaskConfigJson = bytes.Replace(req.TaskConfigJson, []byte(`"params":{}`), []byte(`"params":{"reqid":"ignored-id","sequence":99,"model_name":"ignored-model","opaque":false}`), 1)
hash, err := configread.ExecutionBindingSHA256(req.TaskConfigJson, req.ProvidersJson, req.SipRevision)
if err != nil {
t.Fatal(err)
}
req.BindingSha256 = hash
attempts := 0
s := activatedApprovedServer(t, now, filepath.Join(t.TempDir(), "session.json"), req.DispatcherId, 1,
func(_ context.Context, call ApprovedExecution) error {
attempts++
if call.DispatcherID != req.DispatcherId || call.TenantID != req.TenantId || call.TaskID != req.TaskId || call.SIPRevision != 8 || call.SelectedTrunkID != req.SelectedTrunkId {
t.Fatal("Agent did not receive Dispatcher-authorized call binding")
}
if call.AI.Mode != "asr_only" || call.AI.LLM != nil || call.AI.TTS != nil || call.AI.ASR.Provider.Credential != "sk-******" {
t.Fatal("Agent did not receive the exact approved ASR-only provider snapshot")
}
if string(call.AI.ASR.Params["reqid"]) != `"ignored-id"` || string(call.AI.ASR.Params["opaque"]) != "false" {
t.Fatal("Agent changed the original approved params before request construction")
}
return nil
})
result, err := s.ExecuteApproved(context.Background(), req)
if err != nil || result == nil || !result.Accepted || result.CallId != req.CallId || attempts != 1 {
t.Fatalf("Agent did not accept exactly one mock call: %v %v attempts=%d", result, err, attempts)
}
if _, err := s.ExecuteApproved(context.Background(), req); status.Code(err) != codes.FailedPrecondition || attempts != 1 {
t.Fatalf("accepted call cannot be replayed: err=%v attempts=%d", err, attempts)
}
}
func TestApprovedAgentRejectsMalformedParamsWithoutPersistingAttempt(t *testing.T) {
now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC)
req := approvedTestRequest(t, now)
req.TaskConfigJson = bytes.Replace(req.TaskConfigJson, []byte(`"params":{}`), []byte(`"params":{"nested":{"unexpected":true}}`), 1)
if !strings.Contains(string(req.TaskConfigJson), `"nested":{"unexpected":true}`) {
t.Fatal("malformed params were not inserted into fixture")
}
hash, err := configread.ExecutionBindingSHA256(req.TaskConfigJson, req.ProvidersJson, req.SipRevision)
if err != nil {
t.Fatal(err)
}
req.BindingSha256 = hash
state := filepath.Join(t.TempDir(), "session.json")
attempts := 0
s := activatedApprovedServer(t, now, state, req.DispatcherId, 1,
func(context.Context, ApprovedExecution) error { attempts++; return nil })
_, err = s.ExecuteApproved(context.Background(), req)
if status.Code(err) != codes.InvalidArgument || attempts != 0 || strings.Contains(err.Error(), "example-only-not-a-real-secret") {
t.Fatalf("malformed AI must fail before dialing or leaking credentials: attempts=%d err=%v", attempts, err)
}
if _, statErr := os.Stat(state + ".approved"); !os.IsNotExist(statErr) {
t.Fatalf("no attempt should be durable before AI snapshot validation: %v", statErr)
}
}