package rpc import ( "context" "encoding/json" "path/filepath" "testing" "time" "git.ipao.vip/rogee/go-sip/internal/configread" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func TestExecuteApprovedRejectsInvalidOrDisabledTaskLineBeforeAttempt(t *testing.T) { for _, tc := range []struct { name, trunks string code codes.Code }{ {"disabled selected line", `[{"trunk_id":"trunk-mock","concurrency":0}]`, codes.FailedPrecondition}, {"unlisted selected line", `[{"trunk_id":"other-line","concurrency":5}]`, codes.FailedPrecondition}, {"legacy format", `["trunk-mock"]`, codes.InvalidArgument}, {"missing concurrency", `[{"trunk_id":"trunk-mock"}]`, codes.InvalidArgument}, {"negative concurrency", `[{"trunk_id":"trunk-mock","concurrency":-1}]`, codes.InvalidArgument}, {"duplicate line IDs", `[{"trunk_id":"trunk-mock","concurrency":1},{"trunk_id":"trunk-mock","concurrency":2}]`, codes.InvalidArgument}, } { t.Run(tc.name, func(t *testing.T) { now := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC) req := approvedTestRequest(t, now) var task map[string]json.RawMessage if err := json.Unmarshal(req.TaskConfigJson, &task); err != nil { t.Fatal(err) } task["allowed_trunk_ids"] = json.RawMessage(tc.trunks) var err error req.TaskConfigJson, err = json.Marshal(task) if err != nil { t.Fatal(err) } // Rebind the deliberately invalid task so rejection is about its // structure/authorization, not a mismatched byte digest. req.BindingSha256, err = configread.ExecutionBindingSHA256(req.TaskConfigJson, req.ProvidersJson, req.SipRevision) if err != nil { t.Fatal(err) } attempts := 0 s := activatedApprovedServer(t, now, filepath.Join(t.TempDir(), "agent.json"), req.DispatcherId, 1, func(context.Context, ApprovedExecution) error { attempts++ return nil }) if _, err := s.ExecuteApproved(context.Background(), req); status.Code(err) != tc.code || attempts != 0 { t.Fatalf("attempts=%d err=%v, want code=%v and no attempt", attempts, err, tc.code) } }) } }